1、文件捆绑,秘钥验证,通过则跳转。(可以尝试shellcode)
2、实现函数加密,实现函数存入文件中,秘钥插入后验证,若通过验证,将实现函数解密并跳转执行。(将已加密的实现函数存入pe文件的data部分,此部分在软件运行的时候会先加载,运行时要解密)
1、加密与解密的实现:在加密与解密的过程中,我们利用异或来进行加密,再次异或来进行解密。(异或的性质:对同一个数a异或两次得到的还是a)
2、Shellcode的编写:http://wenku.baidu.com/view/c5d0b1c7d5bbfd0a7956731f.html
Shellcode指南:http://wenku.baidu.com/view/40764642c850ad02de8041da.html?re=view
3、WINDOWS.H是一个最重要的头文件,它包含了其他Windows头文件,这些头文件的某些也包含了其他头文件。这些头文件中最重要的和最基本的是:
WINDEF.H 基本数据类型定义。
WINNT.H 支持Unicode的类型定义。
WINBASE.H Kernel(内核)函数。
WINUSER.H 用户界面函数。
WINGDI.H 图形设备接口函数。
这些头文件定义了Windows的所有资料型态、函数调用、资料结构和常数识别字,它们是Windows文件中的一个重要部分。
Winbase.h中定义了串口通信的函数和结构。
串行接口简称串口,也称串行通信接口(通常指COM接口),是采用串行通信方式的扩展接口。它主要用于串行式逐位数据传输。常见的有一般电脑应用的RS_232(使用25针或9针连接器)和工业电脑应用的半双工RS-485和全双工RS-422.
LoadlibraryA和loadlibraryW虽然都是loadlibrary函数但这两者之间还是有区别的:the difference between LoadLibraryA & LoadLibraryW and foundthat one is ASCII version whereas other is UNICODE version.
loadlibraryA是ASCII版本,加载ASCII码,而loadlibraryWe是Unicode版本,加载Unicode码。
4、可执行外部程序的几个函数:
(1) system
(2) WinExec(“文件名“,打开方式)
如果文件名没有说清路径,那么WinExec函数会首先在本程序所在文件中查找,然后在当前目录中找,接着找Windows系统目录上找,再接着到Windows目录下找,还找不到的话就到系统path变量所指向的地方找,实在找不到就返回程序未找到的错误。
打开方式的话一般有这么几个:
SW_HIDE:程序以无窗口的状态运行
SW_MAXIMIZE :程序以最大化的状态运行
SW_MINIMIZE:程序以最小化的状态运行
SW_SHOW:程序以普通的dos窗口默认大小运行
(3)shell
实现shellcode加密的代码:
#include<stdio.h>
#include<stdlib.h>
#include <stddef.h>
int main(void){
FILE*fp1,*fp2;
charcode1[200];//code2[200];
if(!(fp1=fopen("H:code1.txt","r"))){
printf("File1open error!");
exit(0);
}
if((fp2=fopen("H:code2.txt","w"))==0){
printf("File2open error!");
exit(0);
}
inti=0;
while(!feof(fp1)){
code1[i]=fgetc(fp1)^15;
if(code1[i]!=EOF)
fputc(code1[i],fp2);
else
printf("Writein error!");
i++;
}
if(fclose(fp1)){
printf("Can'tnot close the file!");
exit(0);
}
if(fclose(fp2)){
printf("Can'tnot close the file!");
exit(0);
}
system("pause");
}
主函数代码:
#include "stdio.h"
#include<stdlib.h>
#include<string.h>
#include<windows.h>
void main(){
FILE*fp,*fp2;
charstr[10];
charstr1[10];
FILE*fp1;
inti=0;
intsum;
int(*psum)();
unsignedchar sumarra[60];
/*这里将秘钥从U盘读入,自定义密码从软件包中读入,一方面有利于秘钥的更新,
另一方面也有利于以后的升级工作,比如可以将key1升级为一个库,然后通过网络来验证秘钥的合法性*/
if(!(fp=fopen("H:key.txt","r"))){
printf("key.txtopen error!");
exit(0);
}
if(!(fp2=fopen("H:key1.txt","r"))){
printf("key.txtopen error!");
exit(0);
}
fgets(str,10,fp);
fgets(str1,10,fp2);
if(strcmp(str,str1)==0){
printf("thekey is right\n");
if(!(fp1=fopen("H:code2.txt","r"))){
printf("code2.txtopen error!");
exit(0);
}
while(!feof(fp1)){
sumarra[i]=fgetc(fp1)^15;
i++;
}
//summarr的前3个元素是用来调整机器码的,从第四个开始的五个为跳转语句
psum=sumarra+3;
sum= psum(1,2);
printf("Usesumarra to calculate sum, and sum=%d\n\n", sum);
}
else{
printf("thekey is wrong!\n");
exit(0);}
if(fclose(fp)){
printf("can'tnot close the file0!\n");}
if(fclose(fp2)){
printf("can'tnot close the file2!\n");}
if(fclose(fp1)){
printf("can'tnot close the file1!\n");}
system("pause");
}
这是利用函数指针的代码,与我以前写的利用栈溢出的代码相比,它简洁易懂许多。
1、win7系统有较为健全的保护机制,因此,部分实验过程我们无法在win7环境下完成,需要在xp环境下完成。
2、在od从win7转移到xp上时,需要重新设置路径。
3、在查找jmp esp的时候先运行再查找,不然查找结果不全面,影响实验。
4、在实验中.cpp文件和.c文件是不同的。在.cpp中,函数指针不能指向数组,但在.c文件中函数指针可以指向数组。
在.c中,所有的定义要在函数开始时就定义好,不然编译器会报错。
5、在编译源文件时,C编译器和C++编译器都会对符号(函数或变量)名作某些修正,但两者采用的修正方法不同,所以两者生成的目标文件不能互相链接。在C++中使用extern"C"可以让C++符号获得C链接特性。
通常c/c++编译器会根据文件后缀来选择符号修正,所以最好把c的代码放到.c文件中,把c++的代码放到.cpp文件中。
我们在使用vc和vs时,软件默认生成的文件是.cpp而不是.c,所以我们在使用这些软件写c代码时,要注意这点差别,有可能就是这点差别让你整个代码都不能运行。
http://www.cnblogs.com/ahuo/archive/2008/08/12/1265643.html
__cplusplus The name __cplusplus is definedto the value 199711L when compiling a C++translation unit.143)
http://www.cppblog.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html如果什么时候用到了c和c++混合编程,那么可以从这里找点东西。
在老师给的代码的基础上,我将原来代码进行更改,达到了设计目的。在插入U盘前,核心代码是处于加密状态的。当我插入U盘后,软件识别到了password的存在并验证password是否正确,正确则对核心代码解密执行,不正确则抛出异常退出。
在设计的具体完善过程中,我遇到了很多问题。最烦的一个是函数指针不能指向数组的问题,这个问题被我更改代码文件的后缀名解决。但现在还是有一个亟待解决的问题――用debug从代码中提取机器码的 过程中,别人能做成功,我们却总是得不到解决。甚至同样的代码,同样的步骤,我们得到的结果却和别人的结果截然不同,总是不能实际运行。
在这个问题上花了好多时间。一开始准备利用栈溢出漏洞进行,但是由于shellcode编写知识的缺乏导致利用这种方法失败。(这种方法原理上是可行的)然后老师又指点我用函数指针,在函数指针上,经过实践后我认为函数功能还是和栈溢出的功能差不多,都是利用一块内存将我们所要执行的代码装进去然后想办法将代码执行,只是它更方便些,而且代码可以弄得更加简洁。还有一种思路是利用pe文件的加载区,我们在0day的第一章就知道,pe文件它有个数据加载区,如果我们能将我们的代码装入数据区内,那么我们的功能就能实现。(目前这个方法还未成功完成)
在这些方法的实验过程中,其实写功能函数的代码倒不是很难,一直难的就是shellcode的编写,这里一直无法写出甚至是提取出完全合格的shellcode,总是这里或那里有问题。这里的shellcode还是用的老师给的代码。