原理为通过程序A启动游戏主进程,并通过CREATE_SUSPENDED标记挂起,然后向游戏主进程注入dll模块,dll模块中实现游戏进程API调用拦截,逻辑修改等功能。
1、程序A核心代码:
unsigned int CLaunchShellDlg::SimpleThreadProc(void *arg) { CLaunchShellDlg *theMainUI = (CLaunchShellDlg *)arg; //CString strAppFileName = AfxGetApp()->GetProfileString(_T("STARTUP"), _T("APP")); STARTUPINFO si; PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(PROCESS_INFORMATION)); memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); //CString strAppFileName = _T("F:\\游戏专题\\劲舞团Season6.0\\Audition.exe"); //if (CreateProcess(NULL, strAppFileName.GetBuffer(0), NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, _T("F:\\游戏专题\\劲舞团Season6.0"), &si, &pi)) CString strAppFileName = _T("Audition.exe /T3ENTER qzv5TTNleAJTOzsanttRTQCbExhHDUj"); if (CreateProcess(NULL, strAppFileName.GetBuffer(0), NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { HANDLE hToken; TOKEN_PRIVILEGES tp; LUID luid; if (!OpenProcessToken(pi.hProcess,TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,&hToken)) { return 0; } else{ if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) return 0; tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = 1 ? SE_PRIVILEGE_ENABLED : 0; AdjustTokenPrivileges(hToken,FALSE,&tp,0,0,0); } // Calculate decode address for inject dll char *injectdll = "bf2c6528.dll"; DWORD hHandle = (DWORD)LoadLibrary(injectdll); if (hHandle == 0) goto __ERROR__; DWORD hRemoteModule = (DWORD)GetModuleHandle(injectdll); if (hRemoteModule == 0) goto __ERROR__; DWORD pfndecode = (DWORD)GetProcAddress((HMODULE)hHandle, (LPCSTR)MAKELONG(1, 0)); //DWORD pfnMapViewOfFileFake = (DWORD)GetProcAddress((HMODULE)hHandle, (LPCSTR)MAKELONG(2, 0)); FreeLibrary((HMODULE)hHandle); if (pfndecode == 0) goto __ERROR__; // Calculate offset for decode() DWORD offset1 = pfndecode - hRemoteModule; //DWORD offset2 = pfnMapViewOfFileFake - hRemoteModule; hRemoteModule = InjectDll(pi.hProcess, "bf2c6528"); pfndecode = hRemoteModule + offset1; //pfnMapViewOfFileFake = hRemoteModule + offset2; //解决黑屏问题 unsigned char buf[128]; SIZE_T out; //ReadProcessMemory(pi.hProcess, (LPCVOID)0x0044B00E, buf, sizeof(buf), &out); memset(buf, 0x90, sizeof(buf)); WriteProcessMemory(pi.hProcess, (LPVOID)0x0044AFFE, buf, 5, &out); WriteProcessMemory(pi.hProcess, (LPVOID)0x0044B00E, buf, 1, &out); WriteProcessMemory(pi.hProcess, (LPVOID)0x0044B046, buf, 6, &out); #if 0 // JMP to MapViewOfFileFake //buf[0] = 0xe8; buf[5] = 0x90; //DWORD jmpAddr = pfnMapViewOfFileFake - 0x00439D55 - 5; //memcpy(&buf[1], &jmpAddr, 4); //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439D55, buf, 6, &out); // Test Code; JMP to fixed address //buf[0] = 0xe8; buf[1] = 0x3b; buf[2] = 0x1c; buf[3] = 0x3d; //buf[4] = 0x7c; buf[5] = 0x90; //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439D55, buf, 6, &out); //buf[0] = 0x00; //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439CFC, buf, 1, &out); //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439CA6, buf, 1, &out); #endif #if 1 //buf[0] = 0x10; //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439D21, buf, 1, &out); //buf[0] = 0x04; //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439D40, buf, 1, &out); //buf[0] = 0x04; //WriteProcessMemory(pi.hProcess, (LPVOID)0x00439D4D, buf, 1, &out); void *pAddrRemote = ::VirtualAllocEx( pi.hProcess, NULL, 0x100, MEM_COMMIT, PAGE_READWRITE ); DWORD jmpAddr = 0x00439D55; int codeSize = 6; ReadProcessMemory(pi.hProcess, (LPCVOID)jmpAddr, buf, codeSize, &out); WriteProcessMemory(pi.hProcess, (LPVOID)pAddrRemote, buf, codeSize, &out); // JMP [DST], 5 bytes DWORD address = (DWORD)pAddrRemote - jmpAddr - 5; memcpy(&buf[1], &address, 4); buf[0] = 0xE9; buf[5] = 0x90; WriteProcessMemory(pi.hProcess, (LPVOID)jmpAddr, buf, codeSize, &out); // Calculate JMP/CALL address and replace \xff\xff\xff\xff char shellcode[] = "\xff\xb6\x1c\x59\x87\x00\x6a\x00\x50\x8d\x84\x24\xa4\x01\x00\x00\x50\xe8\xff\xff" "\xff\xff\xe9\xff\xff\xff\xff"; int len = sizeof(shellcode) - 1; pAddrRemote = (char *)pAddrRemote + 6; jmpAddr = pfndecode - ((DWORD)pAddrRemote + len - 10) - 5; memcpy(&shellcode[len - 9], &jmpAddr, 4); jmpAddr = 0x00439D5B - ((DWORD)pAddrRemote + len - 5) - 5; memcpy(&shellcode[len - 4], &jmpAddr, 4); BOOL bRet = WriteProcessMemory(pi.hProcess, (LPVOID)pAddrRemote, shellcode, len, &out); #endif #if 0 // Test Code : JMP to original buf[0] = 0xE9; buf[5] = 0x90; pAddrRemote = (char *)pAddrRemote + 6; address = jmpAddr + codeSize - (DWORD)pAddrRemote - 5; memcpy(&buf[1], &address, 4); WriteProcessMemory(pi.hProcess, (LPVOID)pAddrRemote, buf, 6, &out); #endif int ret = ::ResumeThread(pi.hThread); //Sleep(1000);//If this is not here, everything goes to hell //WaitForSingleObject(pi.hProcess,INFINITE); //CloseHandle(pi.hProcess); //CloseHandle(pi.hThread); //theMainUI->shutdownWindows(); } else { goto __ERROR__; } return 0; __ERROR__: ::MessageBox(0, "登录器出现错误", "提示", MB_OK); return -1; }
类似下面代码中出现的进程绝对地址是通过Olldbg分析工具得到的,直接修改对应的代码。
WriteProcessMemory(pi.hProcess, (LPVOID)0x0044AFFE, buf, 5, &out); WriteProcessMemory(pi.hProcess, (LPVOID)0x0044B00E, buf, 1, &out); WriteProcessMemory(pi.hProcess, (LPVOID)0x0044B046, buf, 6, &out);</pre>
2、注入dll代码
模块功能对acv地图数据进行解密,测试了一个文件。模块也测试过用MapViewOfFileFake拦截 MapViewOfFile,只要替换对应的函数跳转地址即可。
char * __stdcall decode(char *fileName, char *lpMapAddress, int size, HANDLE hFile) { if (hFile != NULL) { size = GetFileSize(hFile, 0); } if (stricmp(fileName, "data/009.acv") == 0) { //char str[128]; //memset(str, 0, sizeof(str)); //_itoa(size, str, 10); ////MessageBox(0, fileName, "File Name...", MB_OK); //MessageBox(0, str, "", MB_OK); //char *pMem = (char *)malloc(bufsize); //memcpy(pMem, buf, bufsize); //buf = pMem; HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL); char *buf = (char *)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0); memcpy(buf, lpMapAddress, size); for (int i = 0; i < size; i++) { buf[i] = buf[i] ^ 0x68; } UnmapViewOfFile( (LPCVOID)lpMapAddress ); lpMapAddress = buf; } return lpMapAddress; } #include <stdio.h> #include <string.h> #include <malloc.h> #include <crtdbg.h> char *gMappingAddress = NULL; LPVOID WINAPI MapViewOfFileFake( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap ) { char *buf = (char *)MapViewOfFile( hFileMappingObject, 0x06, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap); //MEMORY_BASIC_INFORMATION mem_info; //int size = (int)VirtualQuery((void*)buf, &mem_info, sizeof(mem_info)); //char str[128]; //memset(str, 0, sizeof(str)); //_itoa(size, str, 10); //MessageBox(0, str, "", MB_OK); //char *pMem = (char *)malloc(size); //memcpy(pMem, buf, size); return buf; } BOOL WINAPI UnmapViewOfFileFake( LPCVOID lpBaseAddress ) { return UnmapViewOfFile(lpBaseAddress); }
注入模块dll 导出函数定义,要隐藏函数,防止被猜解:
EXPORTS 1=decode @1 2=MapViewOfFileFake @2 3=UnmapViewOfFileFake @3</pre>