前两节中介绍了通过远线程进行注入的方法。现在换一种方法——修改进程入口点。(转载请指明出处)
在PE文件中,其中有个字段标识程序入口点位置。我们通过这个字段,到达程序入口点。PE文件的结构我这儿不讨论(我会在之后写关于PE文件的介绍和研究),我只列出一些和程序入口点有关的数据结构
- typedef struct _IMAGE_NT_HEADERS {
- DWORD Signature;
- IMAGE_FILE_HEADER FileHeader;
- IMAGE_OPTIONAL_HEADER32 OptionalHeader;
- } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
- typedef struct _IMAGE_OPTIONAL_HEADER {
- //
- // Standard fields.
- //
- WORD Magic;
- BYTE MajorLinkerVersion;
- BYTE MinorLinkerVersion;
- DWORD SizeOfCode;
- DWORD SizeOfInitializedData;
- DWORD SizeOfUninitializedData;
- DWORD AddressOfEntryPoint;
- DWORD BaseOfCode;
- DWORD BaseOfData;
- //
- // NT additional fields.
- //
- DWORD ImageBase;
- ……
- }
- PIMAGE_DOS_HEADER lpstDosHeader = (PIMAGE_DOS_HEADER)(LPSTR)lpMapFile;
- PIMAGE_NT_HEADERS lpstNtHeaders = (PIMAGE_NT_HEADERS)((LPSTR)lpMapFile + lpstDosHeader->e_lfanew );
- dwPEEntry = lpstNtHeaders->OptionalHeader.AddressOfEntryPoint + lpstNtHeaders->OptionalHeader.ImageBase;
- 01034BD7 > $ 6A 70 push 70
- 01034BD9 . 68 00740001 push 01007400
- 01034BDE . E8 09040000 call 01034FEC
- public _wWinMainCRTStartup
- .text:01034BD7 _wWinMainCRTStartup proc near
- ……
- .text:01034BD7 push 70h
- .text:01034BD9 push offset stru_1007400
- .text:01034BDE call __SEH_prolog
我们得到第一个Call指令位置和Call的地址后,我们就可以考虑将我们的代码注入到傀儡中。因为我们这次要在代码中动态地修改注入的代码,于是我们需要使用ShellCode,毕竟汇编和01之间还是隔一层的。ShellCode也很好得到,我们写完汇编后,查看该处的16进制码即可。
- /*
- $ ==> > 60 pushad
- $+1 > 9C pushfd
- $+2 > 68 11111111 push 11111111 //加载的dll名称
- $+7 > E8 444288A5 call LoadLibraryW //LoadLibraryW地址
- $+C > 50 push eax
- $+D > E8 444288A5 call FreeLibrary //FreeLibrary地址
- $+12 > 9D popfd
- $+13 > 61 popad
- $+14 >- E9 495399B6 jmp 33333333 //跳转到第一个call函数开始
- */
- BYTE lpShellCode[] = {
- 0x60,
- 0x9c,
- 0x68,0xcc,0xcc,0xcc,0xcc,
- 0xe8,0xcc,0xcc,0xcc,0xcc,
- 0x50,
- 0xe8,0xcc,0xcc,0xcc,0xcc,
- 0x9d,
- 0x61,
- 0xe9,0xcc,0xcc,0xcc,0xcc
- };
- DWORD dwCallAddrOffset = 0;
- if( FALSE == ReadProcessMemory( hProcess, lpFirstCallAddr, &dwCallAddrOffset, 4, NULL ) ) {
- break;
- }
- // 计算call的目标函数地址
- LPSTR lpRealFuncAddr = lpFirstCallAddr + 4 + dwCallAddrOffset;
- DWORD dwDllPathSize = ( (DWORD) wcslen( lpDllPath ) ) * sizeof(WCHAR);
- LPVOID lpDllPathAddr = VirtualAllocEx( hProcess, NULL, dwDllPathSize, MEM_COMMIT, PAGE_READWRITE );
- if( NULL == lpDllPathAddr ) {
- break;
- }
- if( FALSE == WriteProcessMemory( hProcess, lpDllPathAddr, lpDllPath, dwDllPathSize, NULL) ) {
- break;
- }
- LPLoadLibrary lpFuncLoadLibraryAddr = LoadLibraryW;
- LPFreeLibrary lpFuncFreeLibraryAddr = FreeLibrary;
- if ( NULL == lpFuncLoadLibraryAddr || NULL == FreeLibrary ) {
- break;
- }
- size_t ShellCodeSize = strlen( (char*)lpShellCode ) + 1;
- LPVOID lpShellCodeAddr = VirtualAllocEx( hProcess, NULL, ShellCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
- if ( NULL == lpShellCodeAddr ) {
- break;
- }
- // 修改shellcode
- // 填充DLL路径
- memcpy( lpShellCode + 0x03, &lpDllPathAddr, 4 );
- // 填充LoadLibrary偏移
- DWORD dwCallLoadLibraryOffset = (*(LPDWORD)&lpFuncLoadLibraryAddr) -( (*(LPDWORD)&lpShellCodeAddr) + 0x0C );
- memcpy( lpShellCode + 0x08, &dwCallLoadLibraryOffset, 4 );
- // 填充FreeLibrary偏移
- DWORD dwCallFreeLibraryOffset = (*(LPDWORD)&lpFuncFreeLibraryAddr) - ( (*(LPDWORD)&lpShellCodeAddr) + 0x12 );
- memcpy( lpShellCode + 0x0E, &dwCallFreeLibraryOffset, 4 );
- // 填充返回地址偏移,即原来的Call地址
- DWORD dwRealFuncOffset = (*(LPDWORD)&lpRealFuncAddr) - ( (*(LPDWORD)&lpShellCodeAddr) + 0x19 );
- memcpy( lpShellCode + 0x15, &dwRealFuncOffset, 4 );
- // 写入shellcode
- if( FALSE == WriteProcessMemory( hProcess, lpShellCodeAddr, lpShellCode, ShellCodeSize, NULL ) ) {
- break;
- }
- //计算call的新地址
- DWORD dwNewCallAddrOffset = (*(LPDWORD)&lpShellCodeAddr) - ((*(LPDWORD)&lpFirstCallAddr) + 4 );
- MEMORY_BASIC_INFORMATION stMemBasicInfor = {0};
- if ( FALSE == VirtualQueryEx( hProcess, lpFirstCallAddr, &stMemBasicInfor, sizeof(MEMORY_BASIC_INFORMATION) ) )
- {
- break;
- }
- DWORD dwOldProtect = 0;
- if ( FALSE == VirtualProtectEx( hProcess, stMemBasicInfor.BaseAddress, stMemBasicInfor.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtect ) )
- {
- break;
- }
- if ( FALSE == WriteProcessMemory( hProcess, lpFirstCallAddr, &dwNewCallAddrOffset, 4, NULL ) )
- {
- break;
- }
- VirtualProtectEx( hProcess, stMemBasicInfor.BaseAddress, stMemBasicInfor.RegionSize, dwOldProtect, NULL );