一个破解游戏双开的问题
2013-06-16 16:36
316 查看
游戏名称:新热血英豪
将游戏丢进OD,然后分析后发现使用了CreateMutex创建互斥体来防止游戏躲开,遂按照这个思路走下去。
思路1:
编写注入程序A.exe和hook.dll,A中包含远程注入代码和创建游戏进程代码,hook.dll中使用了inlinehook将CreateMutex挂载到自己写的函数CreateMutexG去。
CreateMutex函数将随即生成一个字符串来代替原来CreateMutex参数中的lpName。以下是hook.dll代码:
#pragma comment(lib, "psapi.lib")
BYTE g_NewCode[7];
HMODULE g_hDllHandle = NULL;
HANDLE g_hProcess = NULL;
LPVOID g_CreateMutexA = NULL;
DWORD g_CreateMutexG = NULL;
char g_CurName[256];
void InlineHook();
void BackupDLL();
HANDLE WINAPI CreateMutexG(SECURITY_ATTRIBUTES*, BOOL, LPCTSTR);
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
BackupDLL();
InlineHook();
// ERROR_SUCCESS
break;
}
case DLL_THREAD_ATTACH:
{
break;
}
case DLL_PROCESS_DETACH:
{
break;
}
case DLL_THREAD_DETACH:
{
break;
}
}
return TRUE;
}
void InlineHook()
{
DWORD dwProtect = 0;
DWORD JmpAddr = (DWORD)CreateMutexG;
g_NewCode[0] = 0xB8;
memcpy(&g_NewCode[1], &JmpAddr, 4);
g_NewCode[5] = 0xFF;
g_NewCode[6] = 0xE0;
::VirtualProtect(g_CreateMutexA, 7, PAGE_EXECUTE_READWRITE, &dwProtect);
::WriteProcessMemory(g_hProcess, g_CreateMutexA, g_NewCode, sizeof(g_NewCode), NULL);
::VirtualProtect(g_CreateMutexA, 7, dwProtect, &dwProtect);
return;
}
void BackupDLL()
{
g_hProcess = ::GetCurrentProcess();
g_hDllHandle = ::LoadLibrary("kernel32.dll");
g_CreateMutexA = (LPVOID)::GetProcAddress(g_hDllHandle, "CreateMutexA");
MODULEINFO Mdl_Info;
LPVOID lpNewDLL = NULL;
::GetModuleInformation(g_hProcess, g_hDllHandle, &Mdl_Info, sizeof(Mdl_Info));
lpNewDLL = ::VirtualAllocEx(
g_hProcess,
NULL,
Mdl_Info.SizeOfImage,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE
);
if (lpNewDLL == NULL)
return;
::WriteProcessMemory(g_hProcess, lpNewDLL, Mdl_Info.lpBaseOfDll, Mdl_Info.SizeOfImage, NULL);
g_CreateMutexG = (DWORD)g_CreateMutexA - (DWORD)Mdl_Info.lpBaseOfDll + (DWORD)lpNewDLL;
return;
}
HANDLE WINAPI CreateMutexG(SECURITY_ATTRIBUTES* sa, BOOL bOwner, LPCTSTR lpName)
{
typedef HANDLE WINAPI CREATEMUTEX(SECURITY_ATTRIBUTES* sa, BOOL bOwner, LPCTSTR lpMutexName);
CREATEMUTEX *pfnCreateMutex = (CREATEMUTEX*)g_CreateMutexG;
char lpNewName[256] = { 0x00 };
time_t t;
srand((unsigned)time(&t));
int n = rand() % 52266;
::wsprintf(lpNewName, "GETAMPED_NIJUUKIDOUBOUSHI_MUTEX_021002%dHackedByPapa", n);
// ::wsprintf(lpNewName, "%sHackedByPapa", lpName);
HANDLE hMutex = pfnCreateMutex(sa, bOwner, lpNewName);
int i = GetLastError();
char text[256];
strcpy(g_CurName, lpNewName);
::wsprintf(text, "%d - %s", i, lpNewName);
HANDLE hFile = CreateFile("1.txt",
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
DWORD dw = 0;
WriteFile(hFile, text, strlen(text), &dw, NULL);
CloseHandle(hFile);
//
return hMutex;
}
CreateFile函数是为了方便查看函数的返回信息。
运行注入程序,点击按钮进行创建和注入进程,第一次1.txt的信息返回值为0(ERROR_SUCCESS),第二次返回是183(ERROR_ALREADY_EXISTS),失败!
思路2:
直接修改汇编代码:
004221B0 /$ 81EC BC020000 sub esp,0x2BC
004221B6 |. A1 14104300 mov eax,dword ptr ds:[0x431014]
004221BB |. 33C4 xor eax,esp
004221BD |. 898424 B80200>mov dword ptr ss:[esp+0x2B8],eax
004221C4 |. 57 push edi
004221C5 |. 8BBC24 CC0200>mov edi,dword ptr ss:[esp+0x2CC]
004221CC |. 68 ADE74200 push amped.0042E7AD ; /MutexName = "ETAMPED_NIJUUKIDOUBOUSHI_MUTEX_021002" ; lpName, 即Mutex名称
004221D1 |. 6A 00 push 0x0 ; |InitialOwner = FALSE
004221D3 |. 6A 00 push 0x0 ; |pSecurity = NULL
004221D5 |. FF15 1CE04200 call dword ptr ds:[<&KERNEL32.CreateMute>; \CreateMutexA
004221DB |. FF15 18E04200 call dword ptr ds:[<&KERNEL32.GetLastErr>; [GetLastError
004221E1 |. 3D B7000000 cmp eax,0xB7
|. 75 2A jnz Xamped.00422212 ;直接将jnz修改为jmp.[/b][/color]
004221E8 |. 6A 00 push 0x0 ; /lParam = 0
004221EA |. 68 60214200 push amped.00422160 ; |Callback = amped.00422160
004221EF |. FF15 50E14200 call dword ptr ds:[<&USER32.EnumWindows>>; \EnumWindows
004221F5 |. B8 01000000 mov eax,0x1
004221FA |. 5F pop edi
004221FB |. 8B8C24 B80200>mov ecx,dword ptr ss:[esp+0x2B8]
00422202 |. 33CC xor ecx,esp
00422204 |. E8 35010000 call amped.0042233E
00422209 |. 81C4 BC020000 add esp,0x2BC
0042220F |. C2 1000 retn 0x10
直接修改加粗的代码,jnz改je/jmp,运行两次游戏,第一次显示0,第二次显示183,还是失败。
将游戏丢进OD,然后分析后发现使用了CreateMutex创建互斥体来防止游戏躲开,遂按照这个思路走下去。
思路1:
编写注入程序A.exe和hook.dll,A中包含远程注入代码和创建游戏进程代码,hook.dll中使用了inlinehook将CreateMutex挂载到自己写的函数CreateMutexG去。
CreateMutex函数将随即生成一个字符串来代替原来CreateMutex参数中的lpName。以下是hook.dll代码:
#pragma comment(lib, "psapi.lib")
BYTE g_NewCode[7];
HMODULE g_hDllHandle = NULL;
HANDLE g_hProcess = NULL;
LPVOID g_CreateMutexA = NULL;
DWORD g_CreateMutexG = NULL;
char g_CurName[256];
void InlineHook();
void BackupDLL();
HANDLE WINAPI CreateMutexG(SECURITY_ATTRIBUTES*, BOOL, LPCTSTR);
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
BackupDLL();
InlineHook();
// ERROR_SUCCESS
break;
}
case DLL_THREAD_ATTACH:
{
break;
}
case DLL_PROCESS_DETACH:
{
break;
}
case DLL_THREAD_DETACH:
{
break;
}
}
return TRUE;
}
void InlineHook()
{
DWORD dwProtect = 0;
DWORD JmpAddr = (DWORD)CreateMutexG;
g_NewCode[0] = 0xB8;
memcpy(&g_NewCode[1], &JmpAddr, 4);
g_NewCode[5] = 0xFF;
g_NewCode[6] = 0xE0;
::VirtualProtect(g_CreateMutexA, 7, PAGE_EXECUTE_READWRITE, &dwProtect);
::WriteProcessMemory(g_hProcess, g_CreateMutexA, g_NewCode, sizeof(g_NewCode), NULL);
::VirtualProtect(g_CreateMutexA, 7, dwProtect, &dwProtect);
return;
}
void BackupDLL()
{
g_hProcess = ::GetCurrentProcess();
g_hDllHandle = ::LoadLibrary("kernel32.dll");
g_CreateMutexA = (LPVOID)::GetProcAddress(g_hDllHandle, "CreateMutexA");
MODULEINFO Mdl_Info;
LPVOID lpNewDLL = NULL;
::GetModuleInformation(g_hProcess, g_hDllHandle, &Mdl_Info, sizeof(Mdl_Info));
lpNewDLL = ::VirtualAllocEx(
g_hProcess,
NULL,
Mdl_Info.SizeOfImage,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE
);
if (lpNewDLL == NULL)
return;
::WriteProcessMemory(g_hProcess, lpNewDLL, Mdl_Info.lpBaseOfDll, Mdl_Info.SizeOfImage, NULL);
g_CreateMutexG = (DWORD)g_CreateMutexA - (DWORD)Mdl_Info.lpBaseOfDll + (DWORD)lpNewDLL;
return;
}
HANDLE WINAPI CreateMutexG(SECURITY_ATTRIBUTES* sa, BOOL bOwner, LPCTSTR lpName)
{
typedef HANDLE WINAPI CREATEMUTEX(SECURITY_ATTRIBUTES* sa, BOOL bOwner, LPCTSTR lpMutexName);
CREATEMUTEX *pfnCreateMutex = (CREATEMUTEX*)g_CreateMutexG;
char lpNewName[256] = { 0x00 };
time_t t;
srand((unsigned)time(&t));
int n = rand() % 52266;
::wsprintf(lpNewName, "GETAMPED_NIJUUKIDOUBOUSHI_MUTEX_021002%dHackedByPapa", n);
// ::wsprintf(lpNewName, "%sHackedByPapa", lpName);
HANDLE hMutex = pfnCreateMutex(sa, bOwner, lpNewName);
int i = GetLastError();
char text[256];
strcpy(g_CurName, lpNewName);
::wsprintf(text, "%d - %s", i, lpNewName);
HANDLE hFile = CreateFile("1.txt",
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
DWORD dw = 0;
WriteFile(hFile, text, strlen(text), &dw, NULL);
CloseHandle(hFile);
//
return hMutex;
}
CreateFile函数是为了方便查看函数的返回信息。
运行注入程序,点击按钮进行创建和注入进程,第一次1.txt的信息返回值为0(ERROR_SUCCESS),第二次返回是183(ERROR_ALREADY_EXISTS),失败!
思路2:
直接修改汇编代码:
004221B0 /$ 81EC BC020000 sub esp,0x2BC
004221B6 |. A1 14104300 mov eax,dword ptr ds:[0x431014]
004221BB |. 33C4 xor eax,esp
004221BD |. 898424 B80200>mov dword ptr ss:[esp+0x2B8],eax
004221C4 |. 57 push edi
004221C5 |. 8BBC24 CC0200>mov edi,dword ptr ss:[esp+0x2CC]
004221CC |. 68 ADE74200 push amped.0042E7AD ; /MutexName = "ETAMPED_NIJUUKIDOUBOUSHI_MUTEX_021002" ; lpName, 即Mutex名称
004221D1 |. 6A 00 push 0x0 ; |InitialOwner = FALSE
004221D3 |. 6A 00 push 0x0 ; |pSecurity = NULL
004221D5 |. FF15 1CE04200 call dword ptr ds:[<&KERNEL32.CreateMute>; \CreateMutexA
004221DB |. FF15 18E04200 call dword ptr ds:[<&KERNEL32.GetLastErr>; [GetLastError
004221E1 |. 3D B7000000 cmp eax,0xB7
|. 75 2A jnz Xamped.00422212 ;直接将jnz修改为jmp.[/b][/color]
004221E8 |. 6A 00 push 0x0 ; /lParam = 0
004221EA |. 68 60214200 push amped.00422160 ; |Callback = amped.00422160
004221EF |. FF15 50E14200 call dword ptr ds:[<&USER32.EnumWindows>>; \EnumWindows
004221F5 |. B8 01000000 mov eax,0x1
004221FA |. 5F pop edi
004221FB |. 8B8C24 B80200>mov ecx,dword ptr ss:[esp+0x2B8]
00422202 |. 33CC xor ecx,esp
00422204 |. E8 35010000 call amped.0042233E
00422209 |. 81C4 BC020000 add esp,0x2BC
0042220F |. C2 1000 retn 0x10
直接修改加粗的代码,jnz改je/jmp,运行两次游戏,第一次显示0,第二次显示183,还是失败。
相关文章推荐
- 知乎问题"房间里100个人,每人1000元,他们玩一个游戏,每轮游戏中,每个人拿出1元,随机给另一个人,最后他们的财富分布是怎样的"实践解答
- 一个游戏引发的思考(概率问题)
- lua递归函数的编写,为了解决一个游戏当中遇到的复杂问题
- 关于unity动态添加游戏对象问题,如何动态添加一个菜单【三】
- 日本著名数学游戏专家中村义作教授提出这样一个问题:将2520个桔子分给六个儿子
- 一个关于“取数问题”的游戏
- Josephus问题是下面的游戏 N个人从1到N编号 围成一个圈 经过M次传递后拿着热土豆的人被清除离座
- 每一位游戏设计师都必须思考的一个问题
- 关于unity动态添加游戏对象问题,如何动态添加一个菜单【一】
- 关于unity动态添加游戏对象问题,如何动态添加一个菜单【二】
- 一个游戏中的条件概率问题
- 日本著名数学游戏专家中村义作教授提出这样一个问题:将2520个桔子分给六个儿子
- 恺撒生活在充满危险和阴谋的时代. 恺撒面对的最困难的问题是生存. 为了生存, 他决定创造一种密码. 这种密码听起来难以置信, 如果不知 道方法, 没有人可以破解. 你是恺撒军队的一个上尉. 你的工
- 用Unity3D想做一个简单的赛车游戏,现在的问题是转弯的时候很容易出现翻车的情况,求解决思路
- 金币阵列问题。有m*n枚金币在桌面上排成一个金币阵列。每一个金币正面朝上,或背面朝上,分别用0和1表示。 金币阵列游戏的规则是:(1)每次可将任一行金币翻过来放在原来的位置上;(2)每
- 一个游戏引发的思考(概率问题)
- 一个报数游戏js版(约瑟夫环问题)
- 【转】一个报数游戏(约瑟夫环问题)
- 游戏中一个简单的UI问题