看到有人说LoadLibrary("user32.dll"),360要报。(我自己试了下,没报饿。不知道为啥);
于是就有想可不可以内存加载然后运行。
思路很简单:
1:以PE方式把user32.dll(或者其它dll)COPY到程序中。
2:通过重写位表,进行重定位。
3:解决输入表问题。
4:DLL初始化一下。
完成上面4步就可以调用了。我测试的MessageBoxA,没有问题。
后来仔细想想360肯定是HOOK的内核函数,所以好像这样没用。
代码:
// CopySysDll.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <Windows.h> #include <TCHAR.H> #include <STDLIB.H> DWORD g_dwRelocSecAddr = 0; DWORD g_dwOriginalLoadBase = 0; DWORD g_dwRelocSecSize = 0; DWORD g_dwDllMain = 0; BOOL IsPeFromHandle( HANDLE hFile ) { DWORD dwReadBuf; DWORD dwPeFlagOffset; // 读PE头RAW SetFilePointer( hFile, 0x3c, NULL, FILE_BEGIN ); ReadFile( hFile, &dwPeFlagOffset, 4, &dwReadBuf, NULL ); // 读取PE标志 SetFilePointer( hFile, dwPeFlagOffset, NULL, FILE_BEGIN ); ReadFile( hFile, &dwPeFlagOffset, 2, &dwReadBuf, NULL ); if ( 0x4550 == dwPeFlagOffset ) return TRUE; else return FALSE; } DWORD LoadFile( HANDLE hFile ) { DWORD dwNumOfSections; DWORD dwPeFlagOffset; // PE文件标志偏移 DWORD dwReadBuf; // 实际读取的字节数 DWORD dwSizeOfHeaders; // PE头的总大小 DWORD dwSizeOfImage; if ( !IsPeFromHandle( hFile ) ) return 0; // 读PE头RAW SetFilePointer( hFile, 0x3c, NULL, FILE_BEGIN ); ReadFile( hFile, &dwPeFlagOffset, 4, &dwReadBuf, NULL ); // 读取映像装入内存后总尺寸 SetFilePointer( hFile, dwPeFlagOffset+0x50, NULL, FILE_BEGIN ); ReadFile( hFile, &dwSizeOfImage, 4, &dwReadBuf, NULL ); // 读取pe头的总大小 SetFilePointer( hFile, dwPeFlagOffset+0x54, NULL, FILE_BEGIN ); ReadFile( hFile, &dwSizeOfHeaders, 4, &dwReadBuf, NULL ); // 分配内存来装载文件 LPVOID lpBase = VirtualAlloc( NULL, dwSizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ); // 读PE文件头 SetFilePointer( hFile, 0, NULL, FILE_BEGIN ); ReadFile( hFile, lpBase, dwSizeOfHeaders, &dwReadBuf, NULL ); // 得到PE文件相关指针 PIMAGE_DOS_HEADER pDosHeaders = (PIMAGE_DOS_HEADER) lpBase; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS) ( pDosHeaders->e_lfanew + (DWORD) pDosHeaders ); PIMAGE_OPTIONAL_HEADER pOptionalHeader = (PIMAGE_OPTIONAL_HEADER) &( pNtHeaders->OptionalHeader ); PIMAGE_SECTION_HEADER pSecHaeder = IMAGE_FIRST_SECTION( pNtHeaders ); g_dwOriginalLoadBase = pOptionalHeader->ImageBase; g_dwDllMain = pOptionalHeader->AddressOfEntryPoint + (DWORD)lpBase; // 分区块读入内存 dwNumOfSections = pNtHeaders->FileHeader.NumberOfSections; for ( DWORD i = 0; i < dwNumOfSections; i++ ) { DWORD dwOff = SetFilePointer( hFile, (pSecHaeder + i)->PointerToRawData, NULL, FILE_BEGIN ); BOOL bret = ReadFile( hFile, LPVOID( (pSecHaeder+ i)->VirtualAddress + (DWORD)lpBase), (pSecHaeder+i)->SizeOfRawData, &dwReadBuf, NULL ); if ( i == dwNumOfSections - 1 ) { g_dwRelocSecAddr = (DWORD) ( (pSecHaeder+ i)->VirtualAddress + (DWORD)lpBase); g_dwRelocSecSize = (DWORD) ( (pSecHaeder + i)->Misc.VirtualSize ); } } return (DWORD)lpBase; } // 修正重定位表 void Relocation( DWORD dwBase ) { // 得到实际加载地址和默认加载地址的差值 DWORD dwNum; dwNum = dwBase - g_dwOriginalLoadBase; DWORD dwMax = g_dwRelocSecAddr + g_dwRelocSecSize; while ( g_dwRelocSecAddr < dwMax ) { DWORD dwRelocRva = *( (DWORD*) g_dwRelocSecAddr ); g_dwRelocSecAddr += 4; DWORD dwRelocSize = *( (DWORD*) g_dwRelocSecAddr ); g_dwRelocSecAddr += 4; // 去悼基址和大小占用的字节,一个重定位数据是2字节。/2得到这组重定个数 dwRelocSize -= 8; dwRelocSize /= 2; WORD wRelocInfo= 0; // 重定位信息 WORD wBak = 0; DWORD dwDataAddr = 0; // 重定位数据的地址 DWORD dwData = 0; // 重定位地址的内容 for ( DWORD i = 0; i < dwRelocSize; i++ ) { wRelocInfo = *(WORD*)g_dwRelocSecAddr; g_dwRelocSecAddr += 2; wBak = wRelocInfo; wBak = wBak>>12; // IMAGE_REL_BASED_HIGHLOW 常量是3,表示重定位整个地址都要修正 if ( wBak == IMAGE_REL_BASED_HIGHLOW ) { // 得到低12位 wRelocInfo = wRelocInfo & 0x0fff; dwDataAddr = dwBase + wRelocInfo + dwRelocRva; // 读出数据 dwData = *(DWORD*)dwDataAddr; dwData = dwData + dwNum; // 写入数据,完成重定位 *(DWORD*)dwDataAddr = dwData; } } } } // 修正输入表函数地址 void UpdateImportTableAddress( DWORD dwBase ) { // 得到输入表IID结构 // 得到PE文件相关指针 PIMAGE_DOS_HEADER pDosHeaders = (PIMAGE_DOS_HEADER) dwBase; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS) ( pDosHeaders->e_lfanew + (DWORD) pDosHeaders ); PIMAGE_OPTIONAL_HEADER pOptionalHeader = (PIMAGE_OPTIONAL_HEADER) &( pNtHeaders->OptionalHeader ); PIMAGE_SECTION_HEADER pSecHaeder = IMAGE_FIRST_SECTION( pNtHeaders ); // 得到输入表 PIMAGE_DATA_DIRECTORY pImaDataDir = &( pOptionalHeader->DataDirectory[1] ); PIMAGE_IMPORT_DESCRIPTOR lpImportTab =(PIMAGE_IMPORT_DESCRIPTOR) LPVOID ( pImaDataDir->VirtualAddress + dwBase ); PIMAGE_IMPORT_DESCRIPTOR lpImportTabBak = lpImportTab; DWORD dwNameAddr = 0; DWORD dwFunAddr = 0; while ( 0 != lpImportTab->Name ) { HMODULE hMod = GetModuleHandle( (LPCTSTR)(DWORD*)(dwBase+lpImportTab->Name) ); if ( !hMod ) { hMod = LoadLibrary( (LPCTSTR)(DWORD*)(dwBase+lpImportTab->Name) ); } // 取得INT OR IAT结构的RAV DWORD* pdwINTRav; DWORD* pdwIATRav; pdwIATRav = (DWORD*) ( (DWORD)dwBase+ lpImportTab->FirstThunk ); if ( lpImportTab->OriginalFirstThunk != 0 ) pdwINTRav = (DWORD*) ( (DWORD)dwBase+ lpImportTab->OriginalFirstThunk ); else pdwINTRav = (DWORD*) ( (DWORD)dwBase+ lpImportTab->FirstThunk ); // 函数名方式得到地址 while ( 0 != *pdwINTRav ) { if ( 0x80000000 > *pdwINTRav ) { // dwNameAddr是IMAGE_IMPORT_BY_NAME结构地址,+2的地方就是函数名字串 dwNameAddr = *pdwINTRav + dwBase; dwFunAddr = (DWORD)GetProcAddress( hMod, (LPCTSTR)(DWORD*)(dwNameAddr+2) ); *pdwIATRav = dwFunAddr; ++pdwINTRav; ++pdwIATRav; } // 序列号方式 else { // 得到函数序列号 DWORD dwSerialNunOfFun; dwSerialNunOfFun = *pdwINTRav ^ 0x80000000; DWORD dwFunAddr = (DWORD)GetProcAddress( hMod, (LPCTSTR)(DWORD*)dwSerialNunOfFun ); *pdwIATRav = dwFunAddr; ++pdwINTRav; ++pdwIATRav; } // endif else } // end while ++lpImportTab; } // end while } FARPROC MyGetProcAddress(HMODULE hModule, LPCSTR lpProcName) { PIMAGE_DOS_HEADER pDOSHeader; PIMAGE_NT_HEADERS pNTHeader; PIMAGE_EXPORT_DIRECTORY pExportDir; LPCSTR *pFunctionName; LPCSTR pszFunName; LPDWORD pFunction; LPWORD pIndex; DWORD n; FARPROC ret = NULL; if ((INVALID_HANDLE_VALUE == hModule) || (NULL == lpProcName)) { goto end; } pDOSHeader = (PIMAGE_DOS_HEADER)hModule; if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) { goto end; } pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDOSHeader + (DWORD)pDOSHeader->e_lfanew); if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) { goto end; } pExportDir = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pDOSHeader + \ (DWORD)pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); if ((DWORD)pExportDir == (DWORD)pDOSHeader) { goto end; } pFunctionName = (LPCSTR *)((DWORD)pExportDir->AddressOfNames + (DWORD)pDOSHeader); pFunction = (LPDWORD)((DWORD)pExportDir->AddressOfFunctions + (DWORD)pDOSHeader); pIndex = (LPWORD)((DWORD)pExportDir->AddressOfNameOrdinals + (DWORD)pDOSHeader); n = pExportDir->NumberOfNames; while (n--) { pszFunName = (LPCSTR)((DWORD)*pFunctionName + (DWORD)pDOSHeader); if (strcmp(pszFunName, lpProcName) == 0) { ret = (FARPROC)(pFunction[*pIndex] + (DWORD)pDOSHeader); break; } pFunctionName++; pIndex++; } end: return ret; } typedef int ( __stdcall *MyMessageBoxA)( HANDLE, LPCSTR, LPCSTR, UINT ); int main(int argc, char* argv[]) { MessageBox( NULL, _T("现在我在user.dll中"), _T("提示"), MB_OK ); TCHAR szSysPathBuffer[MAX_PATH]; int bRet = GetSystemDirectory( szSysPathBuffer, MAX_PATH ); if ( 0 != bRet ) { _tcscat( szSysPathBuffer, _T("\\User32.dll") ); } HANDLE hFile = CreateFile( szSysPathBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); LPVOID lpBase = (LPVOID)LoadFile( hFile ); // 修正重定位 Relocation( (DWORD)lpBase ); // 修正输入表 UpdateImportTableAddress( (DWORD)lpBase ); // DLL初始化 __asm { pushad push 0 push DLL_PROCESS_ATTACH push lpBase mov eax, g_dwDllMain call eax popad } // 哈哈全部完成现在测试下 HMODULE hMod = (HMODULE)(DWORD)lpBase; MyMessageBoxA Fun; Fun = (MyMessageBoxA)MyGetProcAddress( hMod, _T("MessageBoxA") ); TCHAR szText[MAX_PATH] = {0}; TCHAR szTemp[10] = {0}; itoa( (DWORD)Fun, szTemp, 16 ); memcpy( szText, _T("现在MessageBoxA在: "), MAX_PATH ); _tcscat( szText, szTemp ); Fun( NULL, szText, _T("成功了"), MB_OK ); printf("Hello World!\n"); return 0; }