Hi, DarthTon, I'm using #define RCALL_TYPE USE_REMOTE_THD, and I find the D3 will crash sometimes when I call the [UsePower] to monsters. I try to add some delay in it but it doesn't work well.
Is there any idea to fix the crash problem?
Hi, DarthTon, I'm using #define RCALL_TYPE USE_REMOTE_THD, and I find the D3 will crash sometimes when I call the [UsePower] to monsters. I try to add some delay in it but it doesn't work well.
Is there any idea to fix the crash problem?
If it crashes only sometimes, you've got race condition. Use RCALL_TYPE USE_DLL instead, it will execute function in game's main thread.
I have add some sleep for main thread every time when remote thread excute over. It doesn't crash now, but I'm not sure of that, and the game will be a little stuck sime main thread is sleeping.
I do want to use dll injection, but I need time to study it, since I'm new to this, and I'm have not understood your source codes very well.
Hi, DarthTon, I have opened RCALL_TYPE USE_DLL, and I run DarkD3SimpleClient, when it attach to D3 process, it will call Dll.Inject(), but it will return in the middle part, I don't know why.
Code:void CProcess::Attach( DWORD pid ) { Core.m_hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ| PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD, FALSE, pid); Core.m_dwImageBase = Dll.GetModuleAddress(pid, _T("Diablo III.exe")); Core.m_hMainThd = OpenThread(THREAD_QUERY_INFORMATION | SYNCHRONIZE | THREAD_SET_CONTEXT | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, FALSE, GetMainThreadID()); CGlobalData::Instance().RefreshOffsets(); CSNOManager::Instance().InitDB(); CUIManager::Instance().EnumUI(); //EnumAttribList(); #if(RCALL_TYPE == USE_DLL) Dll.Inject(); #endif } DWORD CMemDll::Inject() { HANDLE hThread = NULL; HANDLE hFile = INVALID_HANDLE_VALUE; DWORD dwBytesWritten = 0; LPVOID pCode = NULL; DWORD* pfnThreadRtn = NULL; char DllName[255]; if(!CMemCore::Instance().m_hProcess) return ERROR_INVALID_HANDLE; //Already loaded if(GetModuleAddress(GetProcessId(CMemCore::Instance().m_hProcess), TEXT(DLL_NAME)) !=0 ) return ERROR_SUCCESS; -----------------------------------------------------------------------------------------------return here!!!!!!!!!!!!!!!!!!! hFile = CreateFileA(DLL_NAME, GENERIC_READ, NULL, NULL, OPEN_EXISTING, NULL, NULL); if(hFile == INVALID_HANDLE_VALUE) return GetLastError(); else CloseHandle(hFile); GetFullPathNameA(DLL_NAME, sizeof(DllName), DllName, NULL); CHK_RES(CMemCore::Instance().Allocate(0x200, pCode)); if(!WriteProcessMemory(CMemCore::Instance(). m_hProcess, pCode, (LPCVOID)DllName, strlen(DllName)+1, &dwBytesWritten)) { CMemCore::Instance().Free(pCode); return GetLastError(); } pfnThreadRtn = (DWORD*)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "LoadLibraryA"); if(pfnThreadRtn==NULL) { CMemCore::Instance().Free(pCode); return GetLastError(); } hThread = CreateRemoteThread(CMemCore::Instance().m_hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pfnThreadRtn, pCode, 0, NULL); if(hThread == NULL) { CMemCore::Instance().Free(pCode); return GetLastError(); } WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); CMemCore::Instance().Free(pCode); return ERROR_SUCCESS; }
Return in that place means you already have dll loaded into process. I bet it is so because you closed DarkD3SimpleClient incorrectly last time, and it didn't unload dll. In such cases just relaunch D3.
I have got another big problem when I try to use dll injection. There are two dllmain funtions. One in DarkD3\DSMemory\Main.cpp(concerned with DSUtils.dll), another in DarkD3\DarkD3Detour\Dllmain.cpp(concerned with DarkD3Detour.dll).
It only excute dllmain function in Main.cpp, and it just do nothing.
DarkD3\DSMemory\Main.cpp
DarkD3\DarkD3Detour\Dllmain.cpp:Code:#include "stdafx.h" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
It seems all the codes in folder [DarkD3\DarkD3Detour] are not excuted, since I canot add any breakpoints in them, but they have already been added in the project.Code:// dllmain.cpp : Defines the entry point for the DLL application. #include "stdafx.h" #include "Handler.h" BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { UNREFERENCED_PARAMETER(hModule); UNREFERENCED_PARAMETER(lpReserved); switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: CD3DPresentDetour::Instance().DetourFunction ( CD3DPresentDetour::Instance().PresentAddr(), CD3DPresentDetour::Instance().FuncAddress() ); break; case DLL_PROCESS_DETACH: CD3DPresentDetour::Instance().Restore(); break; } return TRUE; }
So, when I call UserPower(D3Player.cpp), it will loop for ever in DoCall function(Shared.cpp).
Shared.cpp
[CODE]
DWORD CShared:oCall( CALL& call, CALL_RET& ret )
{
memcpy(m_pCallData, &call, sizeof(CALL));
//Wait for execution
while(m_pCallData->valid == VALID_CALL && m_pCallData->state != CallState_Completed)
Sleep(100);-------------------------------------------------------------------------------------------------------->Loop for ever!!!
//Reset call state
RtlZeroMemory(m_pCallData, sizeof(CALL));
memcpy(&ret, m_pRetData, sizeof(CALL_RET));
return ERROR_SUCCESS;
}
[/CDOE]
I suppose Dll injection fails in CD3DPresentDetour::Instance().DetourFunction() because of invalid address of hooked function for your system. And because it is executed in DllMain, dll is unloaded instead of crashing whole app.
Hi, DarthTon, Can I modify the PresentAddr() function as following to get the corrent address?
or just as this:Code:/* Get IDirect3DDevice9::Present address. Hardcoded value */ PVOID CD3DPresentDetour::PresentAddr() { HMODULE hD3DBase = GetModuleHandle(_T("d3d9.dll")); //Offset for my Win8 x64 //return (PVOID)((DWORD)hD3DBase + FUNC_D3D_PRESENT_OFFSET); DWORD dwRet = GetD3DPresent(); return (PVOID)((DWORD)hD3DBase + dwRet); } DWORD CD3DPresentDetour::GetD3DPresent() { // No change }
Code:PVOID CD3DPresentDetour::PresentAddr() { HMODULE hD3DBase = GetModuleHandle(_T("d3d9.dll")); //Offset for my Win8 x64 //return (PVOID)((DWORD)hD3DBase + FUNC_D3D_PRESENT_OFFSET); DWORD dwRet = GetD3DPresent(); return (PVOID)dwRet; }
Or I can calculate the FUNC_D3D_PRESENT_OFFSET as GetD3DPresent() - GetModuleHandle(_T("d3d9.dll"))?
You can, if you manage to get GetD3DPresent() working. You can do it either messing with Diablo direct3D device functions(GetD3DPresent() doesn't work inside Diablo in it's current implementation), or just run function code in standalone app - offset is static relatively to d3d9.dll base.Or I can calculate the FUNC_D3D_PRESENT_OFFSET as GetD3DPresent() - GetModuleHandle(_T("d3d9.dll"))?
Updated to 1.0.6
Hi, DarthTon, the ClickElement(...) doesn't work on Click Tab and Click HandicapToggle.
e.g
Root.NormalLayer.stash_dialog_mainPage.tab_3
Root.TopLayer.GameOptions_main.LayoutRoot.OverlayContainer.Gameplay.HandicapTogg le.
Try CUIManager::ClickSPElement(...)
Dear DarthTon!
I'm currently experimenting with the UIObjects' RECTANGE field. I made some progress, but maybe you have a better solution...
- x,y,r,b is given in the UIRect structure
- real_y = y * (window_height / 1200)
- real_x_nomod = x * (window_height / 1200)
- real_x = real_x * mod, where mod is related to the window_aspect. 1,33 ratio: mod=1.0, 1.6 ratio: mod=1.129, 1.77 ratio: mod=1.1975
I did not tested R and B but I'm sure it'll be the same as X and Y...
Do you have any better, easier transformation of the UIRect coordinates to screen coordinates?
Best regards