模塊隱藏那節課要求完成兩個作業,都是隱藏模塊,本文介紹兩種方法分別如何實現。
方法一:往自己的進程注入游戲主模塊
這個題目的意思是將程序的基址設置成高地址,將0x400000空出來,然后將游戲主模塊拉伸,修復IAT之后,注入進去。這樣做的好處主要是簡單,因為不需要修復重定位表了。缺點也很明顯,很多時候根本沒辦法在0x400000處申請足夠大的內存容納游戲程序。,還有就是有些程序跳轉到OEP之后會卡住,具體原因我也不知道。我這里用dbgview.exe測試,能夠正常啟動,這足夠說明我的代碼沒有大的錯誤。
任務管理器中只會看到控制臺的進程,看不到dbgview的進程:
所謂修復IAT,就是指,將游戲PE的IAT表修復成函數地址,做法也很簡單,遍歷IAT表,loadlibary獲取dll句柄,然后遍歷函數名或函數序號,一個個getprocaddress,將獲取到的函數地址寫入到IAT表就算修復好了。
下面是我的代碼,我只給出關鍵的兩個函數,一個是修復IAT表,一個是注入的函數,完整代碼放在文章最后。
注入代碼
void GameInjectMe()
{ if ((DWORD
)GetModuleHandle(NULL) != (DWORD
)0x20000000){printf("當前進程句柄: 0x%X\n", (DWORD
)GetModuleHandle(NULL));printf("請修改鏈接設置,將ImageBase設置為0x20000000\n");return;}LPVOID pFileBuffer
= NULL;FileToMemory(TEXT("c:\\program32\\dbgview.exe"), &pFileBuffer
);LPVOID pImageBuffer
= NULL;DWORD dwImageSize
= FileBufferToImageBuffer(pFileBuffer
, &pImageBuffer
);PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pFileBuffer
;PIMAGE_NT_HEADERS pNTHeader
= (PIMAGE_NT_HEADERS
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
);PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
)); LPVOID pImageBase
= VirtualAlloc((LPVOID
)pOptionHeader
->ImageBase
, dwImageSize
,MEM_COMMIT
, PAGE_READWRITE
); if (pImageBase
!= (LPVOID
)pOptionHeader
->ImageBase
){printf("錯誤碼:0x%X 在ImageBase(0x%X)處VirtualAlloc失敗\n",GetLastError(),pOptionHeader
->ImageBase
);return;}RepairIAT(pImageBuffer
); memcpy(pImageBase
, pImageBuffer
, dwImageSize
);DWORD dwOEP
= pOptionHeader
->AddressOfEntryPoint
+ pOptionHeader
->ImageBase
;__asm
{jmp dwOEP
}
}
修復IAT代碼
void RepairIAT(LPVOID pImageBuffer
)
{PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pImageBuffer
;PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)(pDosHeader
->e_lfanew
+ (DWORD
)pDosHeader
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
));PIMAGE_SECTION_HEADER pSectionHeader
= \
(PIMAGE_SECTION_HEADER
)((DWORD
)pOptionHeader
+ pPEHeader
->SizeOfOptionalHeader
);
PIMAGE_IMPORT_DESCRIPTOR pImportTable
= (PIMAGE_IMPORT_DESCRIPTOR
)((DWORD
)pImageBuffer
+ \pOptionHeader
->DataDirectory
[1].VirtualAddress
);while (pImportTable
->OriginalFirstThunk
|| pImportTable
->FirstThunk
){HMODULE hModule
= LoadLibraryA((LPCSTR
)(pImportTable
->Name
+ (DWORD
)pImageBuffer
));if (NULL == hModule
){printf("獲取模塊句柄失敗,模塊名: %s\n",(LPCSTR
)(pImportTable
->Name
+ (DWORD
)pImageBuffer
));}PIMAGE_THUNK_DATA32 pThunkData
= (PIMAGE_THUNK_DATA32
)((DWORD
)pImageBuffer
+ \pImportTable
->FirstThunk
);while (*((PDWORD
)pThunkData
) != 0){if ((*((PDWORD
)pThunkData
) & 0x80000000) == 0x80000000){DWORD dwProcAddress
= (DWORD
)GetProcAddress(hModule
,MAKEINTRESOURCE((*((PDWORD
)pThunkData
) & 0x7FFFFFFF))); *((PDWORD
)pThunkData
) = dwProcAddress
;}else{PIMAGE_IMPORT_BY_NAME pIBN
= (PIMAGE_IMPORT_BY_NAME
)(*((PDWORD
)pThunkData
) + \
(DWORD
)pImageBuffer
);DWORD dwProcAddress
= (DWORD
)GetProcAddress(hModule
,(LPCSTR
)pIBN
->Name
);*((PDWORD
)pThunkData
) = dwProcAddress
;}pThunkData
++;}pImportTable
= (PIMAGE_IMPORT_DESCRIPTOR
)((DWORD
)pImportTable
+ sizeof(IMAGE_IMPORT_DESCRIPTOR
)); }
}
其實方法一的局限性我在博客開頭已經分析過了,不過我想了一下發現,其實問題關鍵就是0x400000處可能會申請內存失敗,實際上我們不需要非得在這個地方申請內存,而是可以在任意地方申請,然后根據重定位表,修復地址即可。而這種方式,在方法二里面用到了。
以上是第一種方法的做法,下面是第二種做法,往游戲里注入自己,然后跳轉到入口函數:
方法二:往游戲進程注入自己的主模塊
這種方式不需要手工修復IAT,因為自身進程啟動時操作系統幫我們修復了,我們只需要修復重定位表即可。
原理上圖已經解釋的非常明白了,下面給出關鍵代碼:
重定位表修復代碼
VOID
SetNewImageBase2(LPVOID pImageBuffer
, DWORD dwNewImageBase
)
{PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pImageBuffer
;PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)(pDosHeader
->e_lfanew
+ (DWORD
)pDosHeader
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
));PIMAGE_SECTION_HEADER pSectionHeader
= \
(PIMAGE_SECTION_HEADER
)((DWORD
)pOptionHeader
+ pPEHeader
->SizeOfOptionalHeader
);PIMAGE_BASE_RELOCATION pRelocationTable
= (PIMAGE_BASE_RELOCATION
)((DWORD
)pImageBuffer
+ \pOptionHeader
->DataDirectory
[5].VirtualAddress
);DWORD dwImageBaseDelta
= dwNewImageBase
- pOptionHeader
->ImageBase
; while (pRelocationTable
->VirtualAddress
|| pRelocationTable
->SizeOfBlock
){size_t n
= (pRelocationTable
->SizeOfBlock
- 8) / 2; PWORD pOffset
= (PWORD
)((DWORD
)pRelocationTable
+ 8); for (size_t i
= 0; i
< n
; i
++){if ((pOffset
[i
] & 0xF000) == 0x3000){DWORD dwRva
= pRelocationTable
->VirtualAddress
+ (pOffset
[i
] & 0x0FFF); PDWORD pData
= (PDWORD
)((DWORD
)pImageBuffer
+ dwRva
);*pData
+= dwImageBaseDelta
;}} pRelocationTable
= (PIMAGE_BASE_RELOCATION
)((DWORD
)pRelocationTable
+ pRelocationTable
->SizeOfBlock
);}pOptionHeader
->ImageBase
= dwNewImageBase
;
}
注入代碼
void MeInjectGame()
{HMODULE hModule
= GetModuleHandle(NULL);LPVOID pImageBuffer
= (LPVOID
)hModule
; PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pImageBuffer
;PIMAGE_NT_HEADERS pNTHeader
= (PIMAGE_NT_HEADERS
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
);PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
)); DWORD dwSizeOfImage
= pOptionHeader
->SizeOfImage
;pImageBuffer
= malloc(dwSizeOfImage
);memcpy(pImageBuffer
, hModule
, dwSizeOfImage
);HWND hWnd
= FindWindowA(NULL, "LittleGame");DWORD dwPID
= 0;GetWindowThreadProcessId(hWnd
, &dwPID
);printf("進程id: %d\n", dwPID
); HANDLE hProcess
= OpenProcess(PROCESS_ALL_ACCESS
,FALSE
,dwPID
);LPVOID pGameImageBase
= VirtualAllocEx(hProcess
,NULL,dwSizeOfImage
,MEM_COMMIT
,PAGE_EXECUTE_READWRITE
);if (NULL == pGameImageBase
){printf("在游戲進程申請內存失敗,錯誤碼: %d\n", GetLastError());return;}SetNewImageBase2(pImageBuffer
, (DWORD
)pGameImageBase
);WriteProcessMemory(hProcess
,pGameImageBase
,pImageBuffer
,dwSizeOfImage
,NULL);DWORD dwProcOffset
= (DWORD
)InjectEntry
- (DWORD
)hModule
+ (DWORD
)pGameImageBase
;CreateRemoteThread(hProcess
,NULL,NULL,(LPTHREAD_START_ROUTINE
)dwProcOffset
,NULL,NULL,NULL);
}
入口代碼
DWORD WINAPI
InjectEntry(LPVOID param
)
{while (TRUE
){MessageBox(0,0,0,0);Sleep(5000);}return 0;
}
完整代碼
最后,給出項目完整的代碼。
PE.H
#ifndef PE_HPP_
#define PE_HPP_#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif #include <stdio.h>
#include <WINDOWS.H>
#include <STRING.h>
#include <MALLOC.H>DWORD
FileToMemory(LPCSTR lpszFile
, LPVOID
*pFileBuffer
);
BOOL
MemoryToFile(LPVOID pMemBuffer
, DWORD dwSize
, LPCSTR lpszFile
);
BOOL
Is32PEFile(LPVOID pFileBuffer
, DWORD dwSize
);
DWORD
FileBufferToImageBuffer(LPVOID pFileBuffer
, LPVOID
*pImageBuffer
);
DWORD
ImageBufferToFileBuffer(LPVOID pImageBuffer
, LPVOID
*pFileBuffer
);
DWORD
Align(DWORD dwOffset
, DWORD dwAlign
);
DWORD
RvaToFoa(LPVOID pFileBuffer
, DWORD dwRva
);
DWORD
FoaToRva(LPVOID pFileBuffer
, DWORD dwFoa
);
DWORD
MoveNTHeaderAndSectionHeadersToDosStub(LPVOID pFileBuffer
);
VOID
SetNewImageBase(LPVOID pFileBuffer
, DWORD dwNewImageBase
);
void RepairIAT(LPVOID pImageBuffer
);
DWORD
FileToMemory(LPCSTR lpszFile
, LPVOID
*pFileBuffer
)
{FILE
*pFile
= NULL;DWORD dwFileSize
= 0;pFile
= fopen(lpszFile
, "rb");if (pFile
== NULL){printf("打開文件失敗\n");return 0;}fseek(pFile
, 0, SEEK_END);dwFileSize
= ftell(pFile
);fseek(pFile
, 0, SEEK_SET);*pFileBuffer
= malloc(dwFileSize
);if (*pFileBuffer
== NULL){printf("分配內存失敗\n");fclose(pFile
);return 0;}DWORD dwRead
= fread(*pFileBuffer
, 1, dwFileSize
, pFile
);fclose(pFile
);if (dwRead
!= dwFileSize
){free(*pFileBuffer
);return 0;}return dwRead
;
}
BOOL
Is32PEFile(LPVOID pFileBuffer
, DWORD dwSize
)
{PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pFileBuffer
;PIMAGE_NT_HEADERS pNTHeader
= (PIMAGE_NT_HEADERS
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
);PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
));PIMAGE_SECTION_HEADER pSectionHeader
= \
(PIMAGE_SECTION_HEADER
)((DWORD
)pOptionHeader
+ pPEHeader
->SizeOfOptionalHeader
);if (*((PWORD
)pDosHeader
) != IMAGE_DOS_SIGNATURE
){printf("不是有效的MZ標志\n");return FALSE
;}if (pNTHeader
->Signature
!= IMAGE_NT_SIGNATURE
){printf("不是有效的PE標記\n");return FALSE
;}return TRUE
;
}
DWORD
FileBufferToImageBuffer(LPVOID pFileBuffer
, LPVOID
*pImageBuffer
)
{PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pFileBuffer
;PIMAGE_NT_HEADERS pNTHeader
= (PIMAGE_NT_HEADERS
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
);PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
));PIMAGE_SECTION_HEADER pSectionHeader
= \
(PIMAGE_SECTION_HEADER
)((DWORD
)pOptionHeader
+ pPEHeader
->SizeOfOptionalHeader
);*pImageBuffer
= malloc(pOptionHeader
->SizeOfImage
);if (*pImageBuffer
== NULL){printf("分配內存失敗\n");return 0;}memset(*pImageBuffer
, 0, pOptionHeader
->SizeOfImage
);memcpy(*pImageBuffer
, pFileBuffer
, pOptionHeader
->SizeOfHeaders
);for (int i
= 0; i
< pPEHeader
->NumberOfSections
; i
++){memcpy((LPVOID
)((DWORD
)(*pImageBuffer
) + pSectionHeader
[i
].VirtualAddress
), \
(LPVOID
)((DWORD
)pFileBuffer
+ pSectionHeader
[i
].PointerToRawData
), \pSectionHeader
[i
].SizeOfRawData
);}return pOptionHeader
->SizeOfImage
;
}
DWORD
ImageBufferToFileBuffer(LPVOID pImageBuffer
, LPVOID
*pFileBuffer
)
{PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pImageBuffer
;PIMAGE_NT_HEADERS pNTHeader
= (PIMAGE_NT_HEADERS
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
);PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
));PIMAGE_SECTION_HEADER pSectionHeader
= \
(PIMAGE_SECTION_HEADER
)((DWORD
)pOptionHeader
+ pPEHeader
->SizeOfOptionalHeader
);PIMAGE_SECTION_HEADER pLastSectionHeader
= pSectionHeader
+ pPEHeader
->NumberOfSections
- 1;DWORD dwFileBufferSize
= pLastSectionHeader
->PointerToRawData
+ pLastSectionHeader
->SizeOfRawData
;*pFileBuffer
= malloc(dwFileBufferSize
);if (*pFileBuffer
== NULL){printf("分配內存失敗\n");return 0;}memset(*pFileBuffer
, 0, dwFileBufferSize
);memcpy(*pFileBuffer
, pImageBuffer
, pOptionHeader
->SizeOfHeaders
);for (int i
= 0; i
< pPEHeader
->NumberOfSections
; i
++){memcpy((LPVOID
)((DWORD
)(*pFileBuffer
) + pSectionHeader
[i
].PointerToRawData
), \
(LPVOID
)((DWORD
)pImageBuffer
+ pSectionHeader
[i
].VirtualAddress
), \pSectionHeader
[i
].SizeOfRawData
);}return dwFileBufferSize
;
}
BOOL
MemoryToFile(LPVOID pMemBuffer
, DWORD dwSize
, LPCSTR lpszFile
)
{FILE
*fp
= NULL;fp
= fopen(lpszFile
, "wb+");if (fp
== NULL){printf("打開文件失敗\n");return FALSE
;}DWORD dwWritten
= fwrite(pMemBuffer
, 1, dwSize
, fp
);if (dwWritten
!= dwSize
){printf("寫入了 %d 字節,不等于 %d\n", dwWritten
, dwSize
);fclose(fp
);return FALSE
;}fclose(fp
);return TRUE
;
}
DWORD
Align(DWORD dwOffset
, DWORD dwAlign
)
{if (dwOffset
<= dwAlign
) return dwAlign
;if (dwOffset
% dwAlign
){return (dwOffset
/ dwAlign
+ 1) * dwAlign
;}return dwOffset
;
}
DWORD
RvaToFoa(LPVOID pFileBuffer
, DWORD dwRva
)
{PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pFileBuffer
;PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)(pDosHeader
->e_lfanew
+ (DWORD
)pFileBuffer
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
));PIMAGE_SECTION_HEADER pSectionHeader
= \
(PIMAGE_SECTION_HEADER
)((DWORD
)pOptionHeader
+ pPEHeader
->SizeOfOptionalHeader
);if (dwRva
< pOptionHeader
->SizeOfHeaders
){return dwRva
;}for (int i
= 0; i
< pPEHeader
->NumberOfSections
; i
++){if (dwRva
>= pSectionHeader
[i
].VirtualAddress
&& \dwRva
< pSectionHeader
[i
].VirtualAddress
+ pSectionHeader
[i
].Misc
.VirtualSize
){int offset
= dwRva
- pSectionHeader
[i
].VirtualAddress
;return pSectionHeader
[i
].PointerToRawData
+ offset
;}}printf("找不到RVA %x 對應的 FOA,轉換失敗\n", dwRva
);return 0;
}
DWORD
FoaToRva(LPVOID pFileBuffer
, DWORD dwFoa
)
{PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pFileBuffer
;PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)(pDosHeader
->e_lfanew
+ (DWORD
)pFileBuffer
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
));PIMAGE_SECTION_HEADER pSectionHeader
= \
(PIMAGE_SECTION_HEADER
)((DWORD
)pOptionHeader
+ pPEHeader
->SizeOfOptionalHeader
);if (dwFoa
< pOptionHeader
->SizeOfHeaders
){return dwFoa
;}for (int i
= 0; i
< pPEHeader
->NumberOfSections
; i
++){if (dwFoa
>= pSectionHeader
[i
].PointerToRawData
&& \dwFoa
< pSectionHeader
[i
].PointerToRawData
+ pSectionHeader
[i
].SizeOfRawData
){int offset
= dwFoa
- pSectionHeader
[i
].PointerToRawData
;return pSectionHeader
[i
].VirtualAddress
+ offset
;}}printf("找不到FOA %x 對應的 RVA,轉換失敗\n", dwFoa
);return 0;
}
DWORD
MoveNTHeaderAndSectionHeadersToDosStub(LPVOID pFileBuffer
)
{PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pFileBuffer
;PIMAGE_NT_HEADERS pNTHeader
= (PIMAGE_NT_HEADERS
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
);PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
));PIMAGE_SECTION_HEADER pSectionHeader
= \
(PIMAGE_SECTION_HEADER
)((DWORD
)pOptionHeader
+ pPEHeader
->SizeOfOptionalHeader
);LPVOID pDst
= (LPVOID
)((DWORD
)pDosHeader
+ sizeof(IMAGE_DOS_HEADER
)); DWORD dwRet
= (DWORD
)pNTHeader
- (DWORD
)pDst
; DWORD dwSize
= 4 + sizeof(IMAGE_FILE_HEADER
) + pPEHeader
->SizeOfOptionalHeader
+ \
sizeof(IMAGE_SECTION_HEADER
) * pPEHeader
->NumberOfSections
; LPVOID pSrc
= malloc(dwSize
);if (pSrc
== NULL){printf("分配內存失敗\n");return 0;}memcpy(pSrc
, (LPVOID
)pNTHeader
, dwSize
); memset((LPVOID
)pNTHeader
, 0, dwSize
); memcpy(pDst
, pSrc
, dwSize
); free(pSrc
);pDosHeader
->e_lfanew
= sizeof(IMAGE_DOS_HEADER
); return dwRet
;
}
VOID
SetNewImageBase(LPVOID pFileBuffer
, DWORD dwNewImageBase
)
{PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pFileBuffer
;PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)(pDosHeader
->e_lfanew
+ (DWORD
)pDosHeader
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
));PIMAGE_SECTION_HEADER pSectionHeader
= \
(PIMAGE_SECTION_HEADER
)((DWORD
)pOptionHeader
+ pPEHeader
->SizeOfOptionalHeader
);PIMAGE_BASE_RELOCATION pRelocationTable
= (PIMAGE_BASE_RELOCATION
)((DWORD
)pFileBuffer
+ \
RvaToFoa(pFileBuffer
, pOptionHeader
->DataDirectory
[5].VirtualAddress
));DWORD dwImageBaseDelta
= dwNewImageBase
- pOptionHeader
->ImageBase
; while (pRelocationTable
->VirtualAddress
|| pRelocationTable
->SizeOfBlock
){size_t n
= (pRelocationTable
->SizeOfBlock
- 8) / 2; PWORD pOffset
= (PWORD
)((DWORD
)pRelocationTable
+ 8); for (size_t i
= 0; i
< n
; i
++){if ((pOffset
[i
] & 0xF000) == 0x3000){DWORD dwRva
= pRelocationTable
->VirtualAddress
+ (pOffset
[i
] & 0x0FFF);DWORD dwFoa
= RvaToFoa(pFileBuffer
, dwRva
);PDWORD pData
= (PDWORD
)((DWORD
)pFileBuffer
+ dwFoa
);*pData
+= dwImageBaseDelta
;}}pRelocationTable
= (PIMAGE_BASE_RELOCATION
)((DWORD
)pRelocationTable
+ pRelocationTable
->SizeOfBlock
);}pOptionHeader
->ImageBase
= dwNewImageBase
;
}
VOID
SetNewImageBase2(LPVOID pImageBuffer
, DWORD dwNewImageBase
)
{PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pImageBuffer
;PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)(pDosHeader
->e_lfanew
+ (DWORD
)pDosHeader
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
));PIMAGE_SECTION_HEADER pSectionHeader
= \
(PIMAGE_SECTION_HEADER
)((DWORD
)pOptionHeader
+ pPEHeader
->SizeOfOptionalHeader
);PIMAGE_BASE_RELOCATION pRelocationTable
= (PIMAGE_BASE_RELOCATION
)((DWORD
)pImageBuffer
+ \pOptionHeader
->DataDirectory
[5].VirtualAddress
);DWORD dwImageBaseDelta
= dwNewImageBase
- pOptionHeader
->ImageBase
; while (pRelocationTable
->VirtualAddress
|| pRelocationTable
->SizeOfBlock
){size_t n
= (pRelocationTable
->SizeOfBlock
- 8) / 2; PWORD pOffset
= (PWORD
)((DWORD
)pRelocationTable
+ 8); for (size_t i
= 0; i
< n
; i
++){if ((pOffset
[i
] & 0xF000) == 0x3000){DWORD dwRva
= pRelocationTable
->VirtualAddress
+ (pOffset
[i
] & 0x0FFF); PDWORD pData
= (PDWORD
)((DWORD
)pImageBuffer
+ dwRva
);*pData
+= dwImageBaseDelta
;}} pRelocationTable
= (PIMAGE_BASE_RELOCATION
)((DWORD
)pRelocationTable
+ pRelocationTable
->SizeOfBlock
);}pOptionHeader
->ImageBase
= dwNewImageBase
;
}
void RepairIAT(LPVOID pImageBuffer
)
{PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pImageBuffer
;PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)(pDosHeader
->e_lfanew
+ (DWORD
)pDosHeader
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
));PIMAGE_SECTION_HEADER pSectionHeader
= \
(PIMAGE_SECTION_HEADER
)((DWORD
)pOptionHeader
+ pPEHeader
->SizeOfOptionalHeader
);PIMAGE_IMPORT_DESCRIPTOR pImportTable
= (PIMAGE_IMPORT_DESCRIPTOR
)((DWORD
)pImageBuffer
+ \pOptionHeader
->DataDirectory
[1].VirtualAddress
); while (pImportTable
->OriginalFirstThunk
|| pImportTable
->FirstThunk
){HMODULE hModule
= LoadLibraryA((LPCSTR
)(pImportTable
->Name
+ (DWORD
)pImageBuffer
));if (NULL == hModule
){printf("獲取模塊句柄失敗,模塊名: %s\n",(LPCSTR
)(pImportTable
->Name
+ (DWORD
)pImageBuffer
));}PIMAGE_THUNK_DATA32 pThunkData
= (PIMAGE_THUNK_DATA32
)((DWORD
)pImageBuffer
+ \pImportTable
->FirstThunk
);while (*((PDWORD
)pThunkData
) != 0){if ((*((PDWORD
)pThunkData
) & 0x80000000) == 0x80000000){DWORD dwProcAddress
= (DWORD
)GetProcAddress(hModule
,MAKEINTRESOURCE((*((PDWORD
)pThunkData
) & 0x7FFFFFFF))); *((PDWORD
)pThunkData
) = dwProcAddress
;}else{PIMAGE_IMPORT_BY_NAME pIBN
= (PIMAGE_IMPORT_BY_NAME
)(*((PDWORD
)pThunkData
) + \
(DWORD
)pImageBuffer
);DWORD dwProcAddress
= (DWORD
)GetProcAddress(hModule
,(LPCSTR
)pIBN
->Name
);*((PDWORD
)pThunkData
) = dwProcAddress
;}pThunkData
++;}pImportTable
= (PIMAGE_IMPORT_DESCRIPTOR
)((DWORD
)pImportTable
+ sizeof(IMAGE_IMPORT_DESCRIPTOR
)); }
}#endif
main.cpp
#include "stdafx.h"
#include "PE.h"
#include <MALLOC.H>void GameInjectMe();
void MeInjectGame();
BOOL
EnableDebugPrivilege();
DWORD WINAPI
InjectEntry(LPVOID param
);int main(int argc
, char* argv
[])
{EnableDebugPrivilege(); MeInjectGame();return 0;
}
void GameInjectMe()
{ if ((DWORD
)GetModuleHandle(NULL) != (DWORD
)0x20000000){printf("當前進程句柄: 0x%X\n", (DWORD
)GetModuleHandle(NULL));printf("請修改鏈接設置,將ImageBase設置為0x20000000\n");return;}LPVOID pFileBuffer
= NULL;FileToMemory(TEXT("c:\\program32\\dbgview.exe"), &pFileBuffer
);LPVOID pImageBuffer
= NULL;DWORD dwImageSize
= FileBufferToImageBuffer(pFileBuffer
, &pImageBuffer
);PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pFileBuffer
;PIMAGE_NT_HEADERS pNTHeader
= (PIMAGE_NT_HEADERS
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
);PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
)); LPVOID pImageBase
= VirtualAlloc((LPVOID
)pOptionHeader
->ImageBase
, dwImageSize
,MEM_COMMIT
, PAGE_READWRITE
); if (pImageBase
!= (LPVOID
)pOptionHeader
->ImageBase
){printf("錯誤碼:0x%X 在ImageBase(0x%X)處VirtualAlloc失敗\n",GetLastError(),pOptionHeader
->ImageBase
);return;}RepairIAT(pImageBuffer
); memcpy(pImageBase
, pImageBuffer
, dwImageSize
);DWORD dwOEP
= pOptionHeader
->AddressOfEntryPoint
+ pOptionHeader
->ImageBase
;__asm
{jmp dwOEP
}
}
void MeInjectGame()
{HMODULE hModule
= GetModuleHandle(NULL);LPVOID pImageBuffer
= (LPVOID
)hModule
; PIMAGE_DOS_HEADER pDosHeader
= (PIMAGE_DOS_HEADER
)pImageBuffer
;PIMAGE_NT_HEADERS pNTHeader
= (PIMAGE_NT_HEADERS
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
);PIMAGE_FILE_HEADER pPEHeader
= (PIMAGE_FILE_HEADER
)((DWORD
)pDosHeader
+ pDosHeader
->e_lfanew
+ 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader
= (PIMAGE_OPTIONAL_HEADER32
)((DWORD
)pPEHeader
+ sizeof(IMAGE_FILE_HEADER
)); DWORD dwSizeOfImage
= pOptionHeader
->SizeOfImage
;pImageBuffer
= malloc(dwSizeOfImage
);memcpy(pImageBuffer
, hModule
, dwSizeOfImage
);HWND hWnd
= FindWindowA(NULL, "LittleGame");DWORD dwPID
= 0;GetWindowThreadProcessId(hWnd
, &dwPID
);printf("進程id: %d\n", dwPID
); HANDLE hProcess
= OpenProcess(PROCESS_ALL_ACCESS
,FALSE
,dwPID
);LPVOID pGameImageBase
= VirtualAllocEx(hProcess
,NULL,dwSizeOfImage
,MEM_COMMIT
,PAGE_EXECUTE_READWRITE
);if (NULL == pGameImageBase
){printf("在游戲進程申請內存失敗,錯誤碼: %d\n", GetLastError());return;}SetNewImageBase2(pImageBuffer
, (DWORD
)pGameImageBase
);WriteProcessMemory(hProcess
,pGameImageBase
,pImageBuffer
,dwSizeOfImage
,NULL);DWORD dwProcOffset
= (DWORD
)InjectEntry
- (DWORD
)hModule
+ (DWORD
)pGameImageBase
;CreateRemoteThread(hProcess
,NULL,NULL,(LPTHREAD_START_ROUTINE
)dwProcOffset
,NULL,NULL,NULL);
}DWORD WINAPI
InjectEntry(LPVOID param
)
{while (TRUE
){MessageBox(0,0,0,0);Sleep(5000);}return 0;
}
BOOL
EnableDebugPrivilege()
{HANDLE hToken
;BOOL fOk
=FALSE
;if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES
,&hToken
)){TOKEN_PRIVILEGES tp
;tp
.PrivilegeCount
=1;LookupPrivilegeValue(NULL,SE_DEBUG_NAME
,&tp
.Privileges
[0].Luid
);tp
.Privileges
[0].Attributes
=SE_PRIVILEGE_ENABLED
;AdjustTokenPrivileges(hToken
,FALSE
,&tp
,sizeof(tp
),NULL,NULL);fOk
=(GetLastError()==ERROR_SUCCESS
);CloseHandle(hToken
);}return fOk
;
}
總結
以上是生活随笔為你收集整理的隐藏模块(无模块注入)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。