我有一个遗留应用程序,其中包含一个网格,其中包含我需要提取的数据。
我没有该应用程序的代码,并且无法用正常方式从中获取数据(例如以编程方式选择所有单元格并将其复制到剪贴板中)。
所以我决定使用DLL注入,如“II.The CreateRemoteThread& LoadLibrary技术”一节所述
http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces
我的计划是
第一步是将DLL注入遗留应用程序的地址空间(上面的步骤a)。
我为此编写了以下代码:
int InjectDll (HANDLE hProcess);
int _tmain(int argc, _TCHAR* argv[])
{
printf("DllInjector\n");
/**
* Find out PID of the legacy application (START)
*/
HWND windowHandle = FindWindowW(NULL, L"FORMSSSSS");
DWORD* processID = new DWORD;
GetWindowThreadProcessId(windowHandle, processID);
DWORD delphiAppProcessId = *processID;
/**
* Find out PID of the legacy application (END)
*/
printf("Process ID of legacy app: %lu\n", delphiAppProcessId);
// Now we need the handle of the legacy app
HANDLE hProcess = OpenProcess(
PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
FALSE, delphiAppProcessId);
if (hProcess != NULL)
{
printf("Found handle, ready for injection\n");
int result = InjectDll(hProcess);
CloseHandle( hProcess );
printf("Injection complete, result=%d\n", result);
}
else
{
printf("Handle not found\n");
}
system("pause");
return 0;
}
int InjectDll( HANDLE hProcess )
{
HANDLE hThread;
const char* const szLibPath = "D:\\mycompany\\SampleDll\\Debug\\SampleDll.dll";
void* pLibRemote = 0; // the address (in the remote process) where
// szLibPath will be copied to;
DWORD hLibModule = 0; // base adress of loaded module (==HMODULE);
HMODULE hKernel32 = ::GetModuleHandle(L"Kernel32");
// 1. Allocate memory in the remote process for szLibPath
// 2. Write szLibPath to the allocated memory
pLibRemote = ::VirtualAllocEx( hProcess, NULL, sizeof(szLibPath), MEM_COMMIT, PAGE_READWRITE );
if( pLibRemote == NULL )
return false;
::WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath,sizeof(szLibPath),NULL);
// Load "LibSpy.dll" into the remote process
// (via CreateRemoteThread & LoadLibrary)
hThread = ::CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"LoadLibraryA"),
pLibRemote, 0, NULL );
if( hThread == NULL )
goto JUMP;
::WaitForSingleObject( hThread, INFINITE );
// Get handle of loaded module
::GetExitCodeThread( hThread, &hLibModule );
::CloseHandle( hThread );
JUMP:
::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );
if( hLibModule == NULL ) // (1)
return false;
// Unload "LibSpy.dll" from the remote process
// (via CreateRemoteThread & FreeLibrary)
hThread = ::CreateRemoteThread( hProcess,
NULL, 0,
(LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"FreeLibrary"),
(void*)hLibModule,
0, NULL );
if( hThread == NULL ) // failed to unload
return false;
::WaitForSingleObject( hThread, INFINITE );
::GetExitCodeThread( hThread, &hLibModule );
::CloseHandle( hThread );
// return value of remote FreeLibrary (=nonzero on success)
return hLibModule;
}
一些意见:
-
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
{
OutputDebugStringA("DllMain called: ");
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
OutputDebugStringA("DLL_PROCESS_ATTACH\n");
case DLL_THREAD_ATTACH:
OutputDebugStringA("DLL_THREAD_ATTACH\n");
case DLL_THREAD_DETACH:
OutputDebugStringA("DLL_THREAD_DETACH\n");
case DLL_PROCESS_DETACH:
OutputDebugStringA("DLL_PROCESS_DETACH\n");
break;
}
return TRUE;
}
调用它时,会将文本写入应用程序的标准输出中。
当我运行上面的程序(带有_tmain方法的程序)时,我希望看到文本
DllMain called: DLL_PROCESS_ATTACH
控制台输出中的(表示DLL注入成功)。
但它不会发生。
一个可能的原因是遗留应用程序的PID被错误地确定:
HWND windowHandle = FindWindowW(NULL, L"FORMSSSSS");
DWORD* processID = new DWORD;
GetWindowThreadProcessId(windowHandle, processID);
DWORD delphiAppProcessId = *processID;
但值delphiAppProcessId与任务管理器中显示的PID相同,因此我可以排除这个潜在的错误。
使用调试器我发现执行在带注释(1)的行停止:
JUMP:
::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );
if( hLibModule == NULL ) // (1)
return false;
为了将示例DLL注入标题为“FORMSSSSS”的应用程序的地址空间,我需要更改什么?
更新,2012年9月16日:
我替换了所有出现的
的sizeof(szLibPath)
by pathLength,其中
const int pathLength = strlen(szLibPath)+1;
现在,在
::WaitForSingleObject( hThread, INFINITE );
::GetExitCodeThread( hThread, &hLibModule );
::CloseHandle( hThread );
// return value of remote FreeLibrary (=nonzero on success)
return hLibModule;
}
hLibModule非零,这意味着注射成功。
但是我仍然无法在程序的输出中看到示例DLL的日志输出。
更新,16.09.2012(2):
当我
a)在示例DLL的DllMain中添加对AllocConsole()的调用, b)重建它 c)执行注射程序,
然后会出现一个控制台窗口,它与Delphi应用程序具有相同的图标。
当我从DllMain函数中删除AllocConsole并执行注入应用程序时,控制台窗口不会出现。
因此注射可能确实有效。
答案 0 :(得分:1)
我能看到的最大问题是sizeof(szLibPath)
计算指针的大小。请改用strlen(szLibPath)+1
。
当然,这意味着您的注入将失败,因为LoadLibraryA
收到的路径将被截断。可能还有其他问题,但这是开始的地方。