Witam,
problem, który mnie dotknął jest tak absurdalny, że wątpię, że ktokolwiek tutaj jest w stanie go rozwiązać.
Zatem, tworzę pewien mod do gry, który wykorzystuje DLL injection. Wszystko jest oparte o 32 bitowe binarki (gra, dll, launcher). Problemem jest to, że dla mnie i dla kilkudziesięciu tysięcy innych ludzi z różnymi komputerami wszystko pięknie działa, jednak dzisiaj pojawił się gość z drugiego końca świata, któremu nie działa. Problem jest w miejscu ładowania mojej dllki. Konkretniej, LoadLibrary z parametrem ścieżki do mojej dllki zwraca NULL, a GetLastError zwraca kod błędu 193, który oznacza ERROR_BAD_EXE_FORMAT. W ogóle żeby odczytać ten kod błędu musiałem się nieźle nagimnastykować, ale o tym za chwilę. Ogólnie miałem dostęp do komputera tego człowieka przez teamviewer, sprawdziłem wszystko co właściwie mogłoby powodować błędy (binarka gry, dll, launcher, ponowne pobranie binarek, itd.), i nic właściwie nie znalazłem. OS to Windows 10 64bit.
Teraz trochę kodu:
struct SInjectionInfo
{
unsigned pfnMessageBoxA;
unsigned pfnLoadLibraryA;
unsigned pfnGetLastError;
char filename[260];
char msg[1024];
};
typedef int(__stdcall *MESSAGEBOXA)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
typedef HMODULE(__stdcall *LOADLIBRARYA)(LPCTSTR lpFileName);
typedef DWORD(__stdcall *GETLASTERROR)(void);
DWORD __stdcall Inject(LPVOID lpThreadParameter)
{
SInjectionInfo *info = (SInjectionInfo *)lpThreadParameter;
MESSAGEBOXA pfnMessageBox = (MESSAGEBOXA)info->pfnMessageBoxA;
LOADLIBRARYA pfnLoadLibrary = (LOADLIBRARYA)info->pfnLoadLibraryA;
GETLASTERROR pfnGetLastError = (GETLASTERROR)info->pfnGetLastError;
pfnMessageBox(0, info->filename, info->msg, 0);
HANDLE hdl = pfnLoadLibrary(info->filename);
int n = pfnGetLastError();
if (hdl)
n = 0;
{ // itoa implementation
int i, sign, j;
char c;
if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
i = 0;
do { /* generate digits in reverse order */
info->msg[i++] = n % 10 + 48; /* get next digit */
} while ((n /= 10) > 0); /* delete it */
if (sign < 0)
info->msg[i++] = 45;
info->msg[i] = 0;
int len = i;
for (i = 0, j = len - 1; i<j; i++, j--) {
c = info->msg[i];
info->msg[i] = info->msg[j];
info->msg[j] = c;
}
}
pfnMessageBox(0, info->msg, 0, 0); // tu u mnie wyświetla 0, a u brazylijczyka 193 (zawsze)
return 1;
}
const char *InjectDll(HANDLE hProcess, const char* szDllPath)
{
const char *result = "unknown result";
SIZE_T bytesWritten = 0;
const int iCodeSize = 2000;
void* pRmtCode = VirtualAllocEx(hProcess, NULL, iCodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, pRmtCode, (void *)Inject, iCodeSize, &bytesWritten);
SInjectionInfo info;
strcpy(info.filename, szDllPath);
strcpy(info.msg, "Injector");
info.pfnMessageBoxA = (unsigned)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
info.pfnLoadLibraryA = (unsigned)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
info.pfnGetLastError = (unsigned)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetLastError");
void* pRmtInfo = VirtualAllocEx(hProcess, NULL, sizeof(SInjectionInfo), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
WriteProcessMemory(hProcess, pRmtInfo, (void *)&info, sizeof(SInjectionInfo), &bytesWritten);
FlushInstructionCache(hProcess, 0, 0);
DWORD threadId = 0;
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pRmtCode, pRmtInfo, 0, &threadId);
if (hThread && hThread != INVALID_HANDLE_VALUE)
{
WaitForSingleObject(hThread, INFINITE);
DWORD dwExitCode = 0;
GetExitCodeThread(hThread, &dwExitCode);
if (dwExitCode != 0)
{
result = 0;
}
else
{
result = "initialization of client failed";
}
CloseHandle(hThread);
}
else
{
result = "can not create remote thread";
}
return result;
}
Jak widać, specjalnie napisałem funkcję Inject aby tylko poznać kod błędu. Ścieżka do dllki została sprawdzona, wszystkie pointery, i inne, i wszystko się zgadza. To wygląda tak, jakby jego Windows odgórnie wiedział, że mój plik DLL jest 64 bitowy, i nie chciał go załadować. Lub ewentualnie Windows w tym miejscu:
GetModuleHandleA("kernel32.dll")
ładuje kernel32.dll 64 bitowe, w 32 bitowym launcherze...