代码:
#include "stdafx.h" #include <winnt.h> #pragma warning(disable:4102) typedef HMODULE (WINAPI *LOADLIBRARYA)(LPCSTR lpLibFileName); typedef FARPROC (WINAPI *GETPROCADDRESS)(HMODULE hModule, LPCSTR pszProcName); typedef DWORD (WINAPI *GETLASTERROR)(); typedef LPVOID (WINAPI *VIRTUALALLOC)(LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect); typedef BOOL (WINAPI *VIRTUALFREE)(LPVOID lpAddress, DWORD dwSize, DWORD dwFreeType); typedef BOOL (WINAPI *FREELIBRARY)(HMODULE hModule); typedef void (WINAPI *OUTPUTDEBUGSTRINGA)(LPCSTR lpOutputString); typedef VOID (WINAPI *SLEEP)(DWORD dwMilliseconds); typedef void (WINAPI *MYCOPYMEMORY)(LPVOID lpDst, LPCVOID lpSrc, DWORD dwLength); typedef BOOL (WINAPI *PDLLMAIN)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); #define THUNK_BEGIN_TAG \ __asm _emit 't' \ __asm _emit 'h' \ __asm _emit 'u' \ __asm _emit 'n' \ __asm _emit 'k' \ __asm _emit '_' \ __asm _emit 'b' \ __asm _emit 'e' \ __asm _emit 'g' \ __asm _emit 'i' \ __asm _emit 'n' #define THUNK_BEGIN_STR "thunk_begin" #define THUNK_END_TAG \ __asm _emit 't' \ __asm _emit 'h' \ __asm _emit 'u' \ __asm _emit 'n' \ __asm _emit 'k' \ __asm _emit '_' \ __asm _emit 'e' \ __asm _emit 'n' \ __asm _emit 'd' #define THUNK_END_STR "thunk_end" #define CODE_BEGIN_TAG \ __asm _emit 'c' \ __asm _emit 'o' \ __asm _emit 'd' \ __asm _emit 'e' \ __asm _emit '_' \ __asm _emit 'b' \ __asm _emit 'e' \ __asm _emit 'g' \ __asm _emit 'i' \ __asm _emit 'n' #define CODE_BEGIN_STR "code_begin" #pragma check_stack(off) #pragma pack(push, 8) __declspec(naked) void TestCode() { // 临时变量 DWORD offsetLabel; HMODULE hKernel32; LOADLIBRARYA pLoadLibraryA; GETPROCADDRESS pGetProcAddress; FREELIBRARY pFreeLibrary; //VIRTUALALLOC pVirtualAlloc; MYCOPYMEMORY pCopyMemory; OUTPUTDEBUGSTRINGA pOutputDbgStringA; SLEEP pSleep; // 起始标志 THUNK_BEGIN_TAG __asm { //// module //_RO_dwKernel32Base: // INT 3 // INT 3 // INT 3 // INT 3 // api地址空间 使用的时候外部程序填写 _RO_LoadLibraryA: INT 3 INT 3 INT 3 INT 3 _RO_GetProcAddress: INT 3 INT 3 INT 3 INT 3 _RO_FreeLibrary: INT 3 INT 3 INT 3 INT 3 // string _RO_szKernel32: // db "kernel32.dll",0 13 _emit 'K' _emit 'e' _emit 'r' _emit 'n' _emit 'e' _emit 'l' _emit '3' _emit '2' _emit '.' _emit 'd' _emit 'l' _emit 'l' _emit '\0' _RO_szOutputDebugStringA: // db "OutputDebugStringA",0 19 _emit 'O' _emit 'u' _emit 't' _emit 'p' _emit 'u' _emit 't' _emit 'D' _emit 'e' _emit 'b' _emit 'u' _emit 'g' _emit 'S' _emit 't' _emit 'r' _emit 'i' _emit 'n' _emit 'g' _emit 'A' _emit '\0' _RO_szSleep: // db "Sleep",0 6 _emit 'S' _emit 'l' _emit 'e' _emit 'e' _emit 'p' _emit '\0' CODE_BEGIN_TAG // INT 3 // 调试 // INT 3 // INT 3 // INT 3 // INT 3 // INT 3 // INT 3 // INT 3 // 主函数 _MAINCODE_BEGIN: PUSHAD PUSHFD MOV EBP, ESP // 给VC构造BP FRAME SUB ESP, 1024 // 临时变量 // 取得偏移量 CALL _GET_EIP _GET_EIP: POP EAX // 获取当前的EIP, 也就是GET_EIP 处的va !!! SUB EAX, OFFSET _GET_EIP // 计算标号实际地址跟编译生成地址的偏移,用offsetLabel 保存 MOV offsetLabel, EAX MOV EBX, EAX // offserLabel // 初始化临时变量 MOV EAX, OFFSET _RO_LoadLibraryA // LoadLibraryA ADD EAX, EBX MOV EAX, DWORD PTR [EAX] MOV pLoadLibraryA, eax MOV EAX, OFFSET _RO_GetProcAddress // GetProcess ADD EAX, EBX MOV EAX, DWORD PTR [EAX] MOV pGetProcAddress, eax MOV EAX, OFFSET _RO_FreeLibrary // FreeLibrary ADD EAX, EBX MOV EAX, DWORD PTR [EAX] MOV pFreeLibrary, eax MOV EAX, OFFSET _PROC_MemCpy // CopyMemory ADD EAX, EBX MOV pCopyMemory, EAX; MOV EAX, OFFSET _RO_szKernel32 // hKernel32 ADD EAX, EBX PUSH EAX CALL DWORD PTR[pLoadLibraryA] MOV hKernel32, EAX // 做测试 MOV EAX, _RO_szOutputDebugStringA ADD EAX, EBX MOV ESI, hKernel32 CALL _PROC_GetProcAddress MOV pOutputDbgStringA, EAX MOV EAX, _RO_szSleep ADD EAX, EBX MOV ESI, hKernel32 CALL _PROC_GetProcAddress MOV pSleep, EAX _TEST: MOV EAX, _RO_szOutputDebugStringA ADD EAX, EBX PUSH EAX CALL DWORD PTR[pOutputDbgStringA] PUSH 0x3E8 CALL DWORD PTR[pSleep] JMP _TEST _MAINCODE_END: XOR EAX, EAX // 函数返回值 MOV ESP, EBP POPFD POPAD RETN 4 // 线程函数有一个参数 } // 子函数 __asm { // 取函数地址 eax=函数名 esi=模块地址 _PROC_GetProcAddress: PUSH EDX PUSH EAX PUSH ESI MOV EDX, OFFSET _RO_GetProcAddress ADD EDX, offsetLabel CALL [EDX] POP EDX RETN } __asm { // 简单的memcpy 函数 _PROC_MemCpy: PUSH EBP MOV EBP,ESP PUSH ECX PUSH EAX PUSH ESI PUSH EDI MOV EDI,DWORD PTR SS:[EBP+08h] // dst MOV ESI,DWORD PTR SS:[EBP+0Ch] // src MOV ECX,DWORD PTR SS:[EBP+10h] // len TEST ECX, ECX JZ __CopyEnd // copy 0字节的.textbss 要出错所以修改 by ranbo XOR EAX,EAX __cpy: LODS BYTE PTR DS:[ESI] STOS BYTE PTR ES:[EDI] LOOP __cpy __CopyEnd: POP EDI POP ESI POP EAX POP ECX MOV ESP,EBP POP EBP RET 0CH } THUNK_END_TAG } #pragma check_stack(off) // 注入一个进程 并load一个dll的代码 __declspec(naked) void LoadLibraryCode() { DWORD offsetLabel; HMODULE hKernel32; // 函数指针 LOADLIBRARYA pLoadLibraryA; GETPROCADDRESS pGetProcAddress; FREELIBRARY pFreeLibrary; VIRTUALALLOC pVirtualAlloc; MYCOPYMEMORY pCopyMemory; OUTPUTDEBUGSTRINGA pOutputDbgStringA; SLEEP pSleep; // loadlibrary时候用的临时变量 PBYTE pbyLibrary; // dll内存数据 // 起始标志 THUNK_BEGIN_TAG __asm { //// 需要load的 dll 内存 指针 外部初始化时候申请内存并填写这个指针 _RO_pbyLibrary: INT 3 INT 3 INT 3 INT 3 // api地址空间 使用的时候外部程序填写 _RO_LoadLibraryA: INT 3 INT 3 INT 3 INT 3 _RO_GetProcAddress: INT 3 INT 3 INT 3 INT 3 _RO_FreeLibrary: INT 3 INT 3 INT 3 INT 3 // string _RO_szKernel32: // db "kernel32.dll",0 13 _emit 'K' _emit 'e' _emit 'r' _emit 'n' _emit 'e' _emit 'l' _emit '3' _emit '2' _emit '.' _emit 'd' _emit 'l' _emit 'l' _emit '\0' _RO_szVirtualAlloc: _emit 'V' _emit 'i' _emit 'r' _emit 't' _emit 'u' _emit 'a' _emit 'l' _emit 'A' _emit 'l' _emit 'l' _emit 'o' _emit 'c' _emit '\0' _RO_szOutputDebugStringA: // db "OutputDebugStringA",0 19 _emit 'O' _emit 'u' _emit 't' _emit 'p' _emit 'u' _emit 't' _emit 'D' _emit 'e' _emit 'b' _emit 'u' _emit 'g' _emit 'S' _emit 't' _emit 'r' _emit 'i' _emit 'n' _emit 'g' _emit 'A' _emit '\0' _RO_szSleep: // db "Sleep",0 6 _emit 'S' _emit 'l' _emit 'e' _emit 'e' _emit 'p' _emit '\0' CODE_BEGIN_TAG // INT 3 // 调试 // INT 3 // INT 3 // INT 3 // INT 3 // INT 3 // INT 3 // INT 3 // 主函数 _MAINCODE_BEGIN: PUSHAD PUSHFD MOV EBP, ESP // 给VC构造BP FRAME SUB ESP, 2048 // 临时变量 // 取得偏移量 CALL _GET_EIP _GET_EIP: POP EAX // 获取当前的EIP, 也就是GET_EIP 处的va !!! SUB EAX, OFFSET _GET_EIP // 计算标号实际地址跟编译生成地址的偏移,用offsetLabel 保存 MOV offsetLabel, EAX MOV EBX, EAX // offserLabel // 初始化临时变量 // lib操作的几个api必须最先初始化 然后handler 之后才能开始调用函数 MOV EAX, OFFSET _RO_pbyLibrary ADD EAX, EBX MOV EAX, DWORD PTR[EAX] MOV pbyLibrary, EAX MOV EAX, OFFSET _RO_LoadLibraryA // LoadLibraryA ADD EAX, EBX MOV EAX, DWORD PTR [EAX] MOV pLoadLibraryA, eax MOV EAX, OFFSET _RO_GetProcAddress // GetProcess ADD EAX, EBX MOV EAX, DWORD PTR [EAX] MOV pGetProcAddress, eax MOV EAX, OFFSET _RO_FreeLibrary // FreeLibrary ADD EAX, EBX MOV EAX, DWORD PTR [EAX] MOV pFreeLibrary, eax // handler MOV EAX, OFFSET _RO_szKernel32 // hKernel32 ADD EAX, EBX PUSH EAX CALL DWORD PTR[pLoadLibraryA] MOV hKernel32, EAX // 做测试用的几个API 用GetProcess得到 MOV EAX, OFFSET _RO_szVirtualAlloc // VirtualAlloc ADD EAX, EBX MOV ESI, hKernel32 CALL _PROC_GetProcAddress MOV pVirtualAlloc, eax MOV EAX, _RO_szOutputDebugStringA ADD EAX, EBX MOV ESI, hKernel32 CALL _PROC_GetProcAddress MOV pOutputDbgStringA, EAX MOV EAX, _RO_szSleep ADD EAX, EBX MOV ESI, hKernel32 CALL _PROC_GetProcAddress MOV pSleep, EAX // 自定义函数初始化 MOV EAX, OFFSET _PROC_MemCpy // CopyMemory ADD EAX, EBX MOV pCopyMemory, EAX; // _TEST: // MOV EAX, _RO_szOutputDebugStringA // ADD EAX, EBX // PUSH EAX // CALL DWORD PTR[pOutputDbgStringA] // // PUSH 0x3E8 // CALL DWORD PTR[pSleep] // JMP _TEST } //------------------------------------------------------------- // C++代码 加载dll // // 1. 申请内存 copy header section 到内存中 PIMAGE_DOS_HEADER pOrgDosHead; PIMAGE_NT_HEADERS pOrgNtHead; PIMAGE_SECTION_HEADER pOrgSecHead; PBYTE pMemoryImage; pOrgDosHead = (PIMAGE_DOS_HEADER)pbyLibrary; pOrgNtHead = (PIMAGE_NT_HEADERS)(pbyLibrary + pOrgDosHead->e_lfanew); pOrgSecHead = IMAGE_FIRST_SECTION(pOrgNtHead); pMemoryImage = (PBYTE)pVirtualAlloc(NULL, pOrgNtHead->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!pMemoryImage) { //__asm int 3; goto _MAINCODE_END; } // copy header pCopyMemory(pMemoryImage, pbyLibrary, pOrgNtHead->OptionalHeader.SizeOfHeaders); // copy section for(int i=0; i< pOrgNtHead->FileHeader.NumberOfSections; i++, pOrgSecHead++) { pCopyMemory( pMemoryImage + pOrgSecHead->VirtualAddress, pbyLibrary + pOrgSecHead->PointerToRawData, pOrgSecHead->SizeOfRawData ); } // 2. 填充导入表 // 指向copy之后的东东 PIMAGE_DOS_HEADER pDosHead; PIMAGE_NT_HEADERS pNtHead; PIMAGE_SECTION_HEADER pSecHead; PIMAGE_OPTIONAL_HEADER pOptHead; PIMAGE_BASE_RELOCATION pBaseReloc; pDosHead = (PIMAGE_DOS_HEADER)pMemoryImage; pNtHead = (PIMAGE_NT_HEADERS)(pMemoryImage + pDosHead->e_lfanew); pSecHead = IMAGE_FIRST_SECTION(pNtHead); pOptHead = &pNtHead->OptionalHeader; if(pOptHead->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size != 0) { PIMAGE_IMPORT_DESCRIPTOR pid; pid=(IMAGE_IMPORT_DESCRIPTOR *) (pMemoryImage + pOptHead->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); // For all imported DLLs while(pid->FirstThunk && pid->Name) { DWORD *pdwThunkRef; DWORD *pdwFuncRef; char *pszDllName; HMODULE hDll; pszDllName=(char *) (pMemoryImage + pid->Name); hDll = pLoadLibraryA(pszDllName); if(hDll==NULL) { pOutputDbgStringA(pszDllName); //__asm int 3; goto _MAINCODE_END; } if(pid->OriginalFirstThunk) { pdwThunkRef = (DWORD *)(pMemoryImage + pid->OriginalFirstThunk); pdwFuncRef = (DWORD *)(pMemoryImage + pid->FirstThunk); } else { pdwThunkRef = (DWORD *)(pMemoryImage + pid->FirstThunk); pdwFuncRef = (DWORD *)(pMemoryImage + pid->FirstThunk); } for( ; *pdwThunkRef; pdwThunkRef++, pdwFuncRef++) { DWORD dwAddr; if(IMAGE_SNAP_BY_ORDINAL(*pdwThunkRef)) { // win 98 需要单独处理 dwAddr = (DWORD)pGetProcAddress(hDll, (LPCSTR)IMAGE_ORDINAL(*pdwThunkRef)); } else { PIMAGE_IMPORT_BY_NAME pName; pName = (PIMAGE_IMPORT_BY_NAME)(pMemoryImage + (*pdwThunkRef)); dwAddr = (DWORD)pGetProcAddress(hDll, (LPCSTR)&pName->Name); } *pdwFuncRef = dwAddr; } pid++; } } //__asm int 3; // 3. 重定位 DWORD delta; delta=(DWORD)pMemoryImage - (DWORD)pOptHead->ImageBase; if((delta!=0) && (pOptHead->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size!=0)) { pBaseReloc = (PIMAGE_BASE_RELOCATION)(pMemoryImage + pOptHead->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); while(pBaseReloc->VirtualAddress != 0) { // 结构 // WORD offset:12; // WORD type:4; int i; PWORD pwItem = (PWORD)((DWORD)pBaseReloc + IMAGE_SIZEOF_BASE_RELOCATION); int nItems = (pBaseReloc->SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) / sizeof(WORD); for(i=0; i<nItems; i++, pwItem++) { DWORD dwType, dwOffset; DWORD *pBlock; dwType = (*pwItem) >> 12; dwOffset = (*pwItem) & 0xFFF; pBlock = (DWORD *)(pMemoryImage + pBaseReloc->VirtualAddress + dwOffset); // 不能使用switch // switch表在函数体之外 而且是绝对地址 引用跳转会出错 if(dwType == IMAGE_REL_BASED_ABSOLUTE) { } else if(dwType == IMAGE_REL_BASED_HIGH) { *((WORD *)pBlock) += HIWORD(delta); } else if(dwType == IMAGE_REL_BASED_LOW) { *((WORD *)pBlock) += LOWORD(delta); } else if(dwType == IMAGE_REL_BASED_HIGHLOW) { *((DWORD *)pBlock) += delta; } else if(dwType == IMAGE_REL_BASED_HIGHADJ) { DWORD adjust; adjust=((*((WORD *)pBlock)) << 16) | (*(pwItem+1)); adjust += delta; adjust += 0x00008000; *((WORD *)pBlock) = HIWORD(adjust); pwItem++; // 这种被占用了 加一次 } else { //__asm int 3; goto _MAINCODE_END; } } pBaseReloc = (PIMAGE_BASE_RELOCATION) ((PBYTE)pBaseReloc + pBaseReloc->SizeOfBlock); } } //__asm int 3; // 4. 运行dllmain PDLLMAIN pDllMain; pDllMain=(PDLLMAIN)(pMemoryImage + pOptHead->AddressOfEntryPoint); pDllMain((HMODULE) pMemoryImage, DLL_PROCESS_ATTACH, NULL); __asm{ _MAINCODE_END: //__asm int 3; MOV ESP, EBP POPFD POPAD XOR EAX, EAX // 函数返回值 RETN 4 // 线程函数有一个参数 } // 子函数 __asm { // 取函数地址 eax=函数名 esi=模块地址 _PROC_GetProcAddress: PUSH EDX PUSH EAX PUSH ESI MOV EDX, OFFSET _RO_GetProcAddress ADD EDX, offsetLabel CALL [EDX] POP EDX RETN } __asm { // 简单的memcpy 函数 _PROC_MemCpy: PUSH EBP MOV EBP,ESP PUSH ECX PUSH EAX PUSH ESI PUSH EDI MOV EDI,DWORD PTR SS:[EBP+08h] // dst MOV ESI,DWORD PTR SS:[EBP+0Ch] // src MOV ECX,DWORD PTR SS:[EBP+10h] // len TEST ECX, ECX JZ __CopyEnd // copy 0字节的.textbss 要出错所以修改 by ranbo XOR EAX,EAX __cpy: LODS BYTE PTR DS:[ESI] STOS BYTE PTR ES:[EDI] LOOP __cpy __CopyEnd: POP EDI POP ESI POP EAX POP ECX MOV ESP,EBP POP EBP RET 0CH } THUNK_END_TAG } #pragma pack(pop) #pragma check_stack // 内部申请的内存 外边要delete掉 PBYTE GetTestCode(UINT& cbCodeSize, UINT& cbFuncOffset) { LPCSTR pcszThunkBegin = THUNK_BEGIN_STR; LPCSTR pcszThunkEnd = THUNK_END_STR; LPCSTR pcszCodeBegin = CODE_BEGIN_STR; UINT cbMemSize = 0; // 整段需要copy的代码长度 UINT cbCodeOffset = 0; // mem开始距离 maincode起始的偏移 需要用这个作为线程起始地址 PBYTE pbyCode = NULL; // 原生代码开始地址 PBYTE pbyMem = NULL; pbyCode = (PBYTE)&TestCode; if (0 != memcmp(pbyCode, pcszThunkBegin, strlen(pcszThunkBegin))) { OutputDebugStringA("pbyCode error thunk begin tag not find!\n"); return NULL; } pbyCode += strlen(pcszThunkBegin); // 计算需要copy的size pbyMem = pbyCode; while(memcmp(pbyMem, pcszThunkEnd, strlen(pcszThunkEnd))) { pbyMem ++; } cbMemSize = (UINT)(pbyMem - pbyCode); // 计算函数起始地址离mem的偏移量 pbyMem = pbyCode; while(memcmp(pbyMem, pcszCodeBegin, strlen(pcszCodeBegin))) { pbyMem ++; } cbCodeOffset = (UINT)(pbyMem - pbyCode + strlen(pcszCodeBegin)); // 生成本地代码 并初始化 pbyMem = new BYTE[cbMemSize]; if (!pbyMem) { return NULL; } memcpy(pbyMem, pbyCode, cbMemSize); // 初始化三个API _RO_LoadLibraryA, _RO_GetProcAddress, _RO_FreeLibrary *(LOADLIBRARYA *)pbyMem = &::LoadLibraryA; *(GETPROCADDRESS *)(pbyMem + 4) = &::GetProcAddress; *(FREELIBRARY *)(pbyMem + 8) = &::FreeLibrary; // 填写返回值 cbCodeSize = cbMemSize; cbFuncOffset = cbCodeOffset; return pbyMem; } void FreeLocalCode(PBYTE pbyCodeMem) { if (pbyCodeMem) { delete[] pbyCodeMem; } } BOOL InjectTestCode(HANDLE hProcess) { BOOL fSucceeded = FALSE; PBYTE pbyInjCode = NULL; UINT cbCodeSize = 0; UINT cbCodeOffset = 0; PBYTE pbyCodeRemote = NULL; DWORD dwOldProtect = 0; DWORD dwNumBytesXferred = 0; HANDLE hThread = NULL; DWORD dwThreadId = 0; // 初始化inject code pbyInjCode = GetTestCode(cbCodeSize, cbCodeOffset); if(!pbyInjCode) { goto finish; } // 在目标进程申请地址,写入代码并启动远程线程 pbyCodeRemote = (PBYTE)VirtualAllocEx(hProcess, NULL, cbCodeSize, MEM_COMMIT | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE); if(!pbyCodeRemote) { goto finish; } if (!VirtualProtectEx(hProcess, pbyCodeRemote, cbCodeSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) { goto finish; } if (!WriteProcessMemory(hProcess, pbyCodeRemote, pbyInjCode, cbCodeSize, &dwNumBytesXferred)) { goto finish; } if ((hThread = CreateRemoteThread(hProcess, NULL, 65536, (LPTHREAD_START_ROUTINE)(pbyCodeRemote+cbCodeOffset), NULL, 0, &dwThreadId)) == NULL) { goto finish; } fSucceeded = TRUE; finish: if(pbyInjCode) { FreeLocalCode(pbyInjCode); } GetLastError(); return fSucceeded; } //----------------------------------------------------------------------- // 测试注入代码到目标进程并load一个dll // BOOL InjectLoadLibCode(HANDLE hProcess, LPCTSTR pszLibName) { BOOL fSucceeded = FALSE; LPCSTR pcszThunkBegin = THUNK_BEGIN_STR; LPCSTR pcszThunkEnd = THUNK_END_STR; LPCSTR pcszCodeBegin = CODE_BEGIN_STR; UINT cbThunkSize = 0; // 整段需要copy的代码长度 UINT cbCodeOffset = 0; // mem开始距离 maincode起始的偏移 需要用这个作为线程起始地址 PBYTE pbyCode = NULL; // 原生代码开始地址 PBYTE pbyThunk = NULL; PBYTE pbyImage = NULL; DWORD cbFileSize=0, cbReadSize=0; HANDLE hLibFile = INVALID_HANDLE_VALUE; // 读取文件 hLibFile = CreateFile(pszLibName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if(hLibFile == INVALID_HANDLE_VALUE) { goto finish; } cbFileSize = GetFileSize(hLibFile, NULL); pbyImage = new BYTE[cbFileSize]; if (!ReadFile(hLibFile, pbyImage, cbFileSize, &cbReadSize, NULL) || cbReadSize!=cbFileSize) { goto finish; } // 构建取代码 pbyCode = (PBYTE)&LoadLibraryCode; if (0 != memcmp(pbyCode, pcszThunkBegin, strlen(pcszThunkBegin))) { OutputDebugStringA("pbyCode error thunk begin tag not find!\n"); return NULL; } pbyCode += strlen(pcszThunkBegin); // 计算需要copy的size pbyThunk = pbyCode; while(memcmp(pbyThunk, pcszThunkEnd, strlen(pcszThunkEnd))) { pbyThunk ++; } cbThunkSize = (UINT)(pbyThunk - pbyCode); // 计算函数起始地址离mem的偏移量 pbyThunk = pbyCode; while(memcmp(pbyThunk, pcszCodeBegin, strlen(pcszCodeBegin))) { pbyThunk ++; } cbCodeOffset = (UINT)(pbyThunk - pbyCode + strlen(pcszCodeBegin)); // 生成本地代码 并初始化 pbyThunk = new BYTE[cbThunkSize]; if (!pbyThunk) { goto finish; } memcpy(pbyThunk, pbyCode, cbThunkSize); // 初始化三个API _RO_LoadLibraryA, _RO_GetProcAddress, _RO_FreeLibrary *(LOADLIBRARYA *)(pbyThunk + 0x04) = &::LoadLibraryA; *(GETPROCADDRESS *)(pbyThunk + 0x08) = &::GetProcAddress; *(FREELIBRARY *)(pbyThunk + 0x0C) = &::FreeLibrary; PBYTE pbyImageRemote = NULL; PBYTE pbyThunkRemote = NULL; DWORD dwOldProtect = 0; DWORD dwNumBytesXferred = 0; HANDLE hThread = NULL; DWORD dwThreadId = 0; // 在目标进程申请地址,写入DLL 的数据 pbyImageRemote = (PBYTE)VirtualAllocEx(hProcess, NULL, cbFileSize, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE); if(!pbyImageRemote) { goto finish; } if (!VirtualProtectEx(hProcess, pbyImageRemote, cbFileSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) { goto finish; } if (!WriteProcessMemory(hProcess, pbyImageRemote, pbyImage, cbFileSize, &dwNumBytesXferred)) { goto finish; } // 将image地址填写到code中 *(PBYTE *)(pbyThunk + 0x0) = pbyImageRemote; // 在目标进程申请地址,写入代码并启动远程线程 pbyThunkRemote = (PBYTE)VirtualAllocEx(hProcess, NULL, cbThunkSize, MEM_COMMIT | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE); if(!pbyThunkRemote) { goto finish; } if (!VirtualProtectEx(hProcess, pbyThunkRemote, cbThunkSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) { goto finish; } if (!WriteProcessMemory(hProcess, pbyThunkRemote, pbyThunk, cbThunkSize, &dwNumBytesXferred)) { goto finish; } if ((hThread = CreateRemoteThread(hProcess, NULL, 65536, (LPTHREAD_START_ROUTINE)(pbyThunkRemote+cbCodeOffset), NULL, 0, &dwThreadId)) == NULL) { goto finish; } fSucceeded = TRUE; finish: if (pbyImage) { delete[] pbyImage; } if(pbyThunk) { delete[] pbyThunk; } GetLastError(); return fSucceeded; }
才写的 用来做一些猥琐的事情
真正找不到模块了
还可以把注入的dll的pe头都擦除
VC编译的时候注意选项, 不能使用 run time check, 还有增量编译也要关掉