遇到一个棘手的问题,求各位帮助解答。同样的远程注入线程的代码(注入到Notepad当中),如果我的程序是MFC或者WTL窗体程序,在注入线程的时候,目标进程就会CRASH,如果我的程序是SDK的窗体程序,目标进程就不会CRASH。
代码如下:(Notepad会在弹出MessageBox之后CRASH在KERNEL32.DLL当中,Message的内容只有"T"而不是"Test")。typedef int (WINAPI *MESSAGEBOX)(HWND,LPCTSTR,LPCTSTR,UINT);typedef struct {
MESSAGEBOX fnMessageBox; // pointer to user32!SendMessage
TCHAR pbText[128 * sizeof(TCHAR)];
} INJDATA, *PINJDATA;static DWORD WINAPI ThreadFunc (INJDATA *pData)
{
int nXferred = 0; // number of chars retrieved by WM_GETTEXT
nXferred = pData->fnMessageBox( NULL, pData->pbText, pData->pbText, MB_OK);
return nXferred;
}static void AfterThreadFunc (void) {
}
DWORD InjectCodeToRemoteThread(DWORD processID)
{
HINSTANCE hUser32;
INJDATA *pDataRemote; // the address (in the remote process) where INJDATA will be copied to;
DWORD *pCodeRemote; // the address (in the remote process) where ThreadFunc will be copied to;
HANDLE hThread = NULL; // the handle to the thread executing the remote copy of ThreadFunc;
DWORD dwThreadId = 0;
DWORD dwNumBytesXferred = 0; // number of bytes written/read to/from the remote process; HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, processID );
if(hProcess == NULL)
return -1;
__try {
hUser32 = GetModuleHandle(__TEXT("user32"));
if (hUser32 == NULL)
__leave; // Initialize INJDATA and then
// copy it to the remote process
INJDATA DataLocal = {
(MESSAGEBOX) GetProcAddress(hUser32, "MessageBoxA"),
_T("Test")
};
if( DataLocal.fnMessageBox == NULL )
__leave;
// 1. Allocate memory in the remote process for INJDATA
// 2. Write a copy of DataLocal to the allocated memory
pDataRemote = (INJDATA*) VirtualAllocEx( hProcess, 0, sizeof(INJDATA), MEM_COMMIT, PAGE_READWRITE );
if (pDataRemote == NULL)
__leave;
WriteProcessMemory( hProcess, pDataRemote, &DataLocal, sizeof(INJDATA), &dwNumBytesXferred );
// Calculate the number of bytes that ThreadFunc occupies
const int cbCodeSize = ((LPBYTE) AfterThreadFunc - (LPBYTE) ThreadFunc); // 1. Allocate memory in the remote process for the injected ThreadFunc
// 2. Write a copy of ThreadFunc to the allocated memory
pCodeRemote = (PDWORD) VirtualAllocEx( hProcess, 0, cbCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if (pCodeRemote == NULL)
__leave;
WriteProcessMemory( hProcess, pCodeRemote, &ThreadFunc, cbCodeSize, &dwNumBytesXferred );
// Start execution of remote ThreadFunc
hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE) pCodeRemote,
pDataRemote, 0 , &dwThreadId);
if (hThread == NULL)
__leave; WaitForSingleObject(hThread, INFINITE); }
__finally {
if ( pDataRemote != 0 )
VirtualFreeEx( hProcess, pDataRemote, 0, MEM_RELEASE ); if ( pCodeRemote != 0 )
VirtualFreeEx( hProcess, pCodeRemote, 0, MEM_RELEASE ); if ( hThread != NULL ) {
CloseHandle(hThread);
}
} return 0;
}
代码如下:(Notepad会在弹出MessageBox之后CRASH在KERNEL32.DLL当中,Message的内容只有"T"而不是"Test")。typedef int (WINAPI *MESSAGEBOX)(HWND,LPCTSTR,LPCTSTR,UINT);typedef struct {
MESSAGEBOX fnMessageBox; // pointer to user32!SendMessage
TCHAR pbText[128 * sizeof(TCHAR)];
} INJDATA, *PINJDATA;static DWORD WINAPI ThreadFunc (INJDATA *pData)
{
int nXferred = 0; // number of chars retrieved by WM_GETTEXT
nXferred = pData->fnMessageBox( NULL, pData->pbText, pData->pbText, MB_OK);
return nXferred;
}static void AfterThreadFunc (void) {
}
DWORD InjectCodeToRemoteThread(DWORD processID)
{
HINSTANCE hUser32;
INJDATA *pDataRemote; // the address (in the remote process) where INJDATA will be copied to;
DWORD *pCodeRemote; // the address (in the remote process) where ThreadFunc will be copied to;
HANDLE hThread = NULL; // the handle to the thread executing the remote copy of ThreadFunc;
DWORD dwThreadId = 0;
DWORD dwNumBytesXferred = 0; // number of bytes written/read to/from the remote process; HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, processID );
if(hProcess == NULL)
return -1;
__try {
hUser32 = GetModuleHandle(__TEXT("user32"));
if (hUser32 == NULL)
__leave; // Initialize INJDATA and then
// copy it to the remote process
INJDATA DataLocal = {
(MESSAGEBOX) GetProcAddress(hUser32, "MessageBoxA"),
_T("Test")
};
if( DataLocal.fnMessageBox == NULL )
__leave;
// 1. Allocate memory in the remote process for INJDATA
// 2. Write a copy of DataLocal to the allocated memory
pDataRemote = (INJDATA*) VirtualAllocEx( hProcess, 0, sizeof(INJDATA), MEM_COMMIT, PAGE_READWRITE );
if (pDataRemote == NULL)
__leave;
WriteProcessMemory( hProcess, pDataRemote, &DataLocal, sizeof(INJDATA), &dwNumBytesXferred );
// Calculate the number of bytes that ThreadFunc occupies
const int cbCodeSize = ((LPBYTE) AfterThreadFunc - (LPBYTE) ThreadFunc); // 1. Allocate memory in the remote process for the injected ThreadFunc
// 2. Write a copy of ThreadFunc to the allocated memory
pCodeRemote = (PDWORD) VirtualAllocEx( hProcess, 0, cbCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if (pCodeRemote == NULL)
__leave;
WriteProcessMemory( hProcess, pCodeRemote, &ThreadFunc, cbCodeSize, &dwNumBytesXferred );
// Start execution of remote ThreadFunc
hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE) pCodeRemote,
pDataRemote, 0 , &dwThreadId);
if (hThread == NULL)
__leave; WaitForSingleObject(hThread, INFINITE); }
__finally {
if ( pDataRemote != 0 )
VirtualFreeEx( hProcess, pDataRemote, 0, MEM_RELEASE ); if ( pCodeRemote != 0 )
VirtualFreeEx( hProcess, pCodeRemote, 0, MEM_RELEASE ); if ( hThread != NULL ) {
CloseHandle(hThread);
}
} return 0;
}
所以有时 CRASH, 你固定cbCodeSize 比如 cbCodeSize = 1024; 试试
第一种
typedef struct {
MESSAGEBOX fnMessageBox; // pointer to user32!SendMessage
CHAR pbText[128 * sizeof(CHAR)];
} INJDATA, *PINJDATA;INJDATA DataLocal = {
(MESSAGEBOX) GetProcAddress(hUser32, "MessageBoxA"),
"Test";
};第二种,最简单,都不需要GetModuleHandleINJDATA DataLocal = {
MessageBox,
_T("Test")
};编译器会根据你当前的字符集选择合适的Call,另外直接使用函数名可以得到函数地址而非跳转地址,所以这样做是安全的。
第二种方式会有问题吧,这个结构会被插入到另一个process中,如果直接使用函数名,调用应该会失败的。
楼主你要不试试把获取MessageBox地址的过程放到ThreadFunc中?
看过了,地址与size都相同。
取到的MessageBoxW的地址是0x7开头吗?
MessageBoxW的地址是0x77d960f2
Three Ways to Inject Your Code into Another Process --- By Robert Kuster
...
The /GZ compiler switch In Debug builds, the /GZ compiler feature is turned on by default. You can use it to catch some errors (see the documentation for details). But what does it mean to our executable?
When /GZ is turned on, the compiler will add some additional code to every function residing in the executable, including a function call (added at the very end of every function) that verifies the ESP stack pointer hasn't changed through our function. But wait, a function call is added to ThreadFunc? That's the road to disaster. Now the remote copy of ThreadFunc will call a function that doesn't exist in the remote process (at least not at the same address).
...答案就是关掉GZ,我的代码也是来源于这片文章,只是学习过程中不仔细,忽略了这一段。还是要谢谢大家的帮助。
Three Ways to Inject Your Code into Another Process --- By Robert Kuster
...
The /GZ compiler switch In Debug builds, the /GZ compiler feature is turned on by default. You can use it to catch some errors (see the documentation for details). But what does it mean to our executable?
When /GZ is turned on, the compiler will add some additional code to every function residing in the executable, including a function call (added at the very end of every function) that verifies the ESP stack pointer hasn't changed through our function. But wait, a function call is added to ThreadFunc? That's the road to disaster. Now the remote copy of ThreadFunc will call a function that doesn't exist in the remote process (at least not at the same address).
...答案就是关掉GZ,我的代码也是来源于这片文章,只是学习过程中不仔细,忽略了这一段。还是要谢谢大家的帮助。