[分享]发一份去年针对某游戏的R3特征封号的一个处理
简单来说就是处理ZwQueryVirtualMemory的,内存dll这种大家都懂的。代码丑...轻喷..
后来游戏增加了ShadowApi也一并处理了..
当时因为X3会检测syscall所以没有在入口直接写hook,能直接hook那里处理的也就不用写这么多了。
顺便问个事情,现在已经隐藏了进程的路径,xt里看进程也是伪造的进程的,但是查看模块的时候,还是能看到模块的路径,有什么方法可以连那里都抹掉吗?(R0处理)
void FuckSearchAPI()
{
VMProtectBegin("SearchApi");
DWORD dw_Sb = 0x30000;
DWORD dw_ZwQSys = 0;
DWORD dw_KernBase = 0;
char ch_Checkzwqadd[20];
int i_Check = 0;
dw_Last4C += 0xFCC00;
//1.搜索KernelBase中的zwq位置 2.在last4C中搜索
//一切照旧
dw_KernBase = (DWORD)GetModuleHandleA("KernelBase.dll");
dw_ZwQSys = (DWORD)GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwQueryVirtualMemory");
unsigned char Uc_zwqSys[] = { 0xE0, 0xE0, 0xE0, 0xE0 };
memcpy(Uc_zwqSys, &dw_ZwQSys, 4);
dw_RighHookAdd = SUNDAY((unsigned char*)dw_KernBase, Uc_zwqSys, 4, 0x4000);
_asm{
mov eax, [dw_RighHookAdd]
add eax,0x4
mov eax, [eax]
mov[dw_ZwQSys],eax
}
unsigned char Uc_zwqSys_last[] = { 0xE0, 0xE0, 0xE0, 0xE0 };
memcpy(Uc_zwqSys_last, &dw_ZwQSys, 4);
dw_RighHookAdd = SUNDAY((unsigned char*)dw_Last4C, Uc_zwqSys_last, 4, dw_Sb);
if (dw_RighHookAdd == NULL)WritePrivateProfileStringA("c", "a", "1", "c:\\xxxx.ini");
else WritePrivateProfileStringA("c", "a", "2", "c:\\xxxx.ini");
dw_RighHookAdd -= 4;
_asm{
mov eax, [dw_RighHookAdd]
mov ebx, [dw_ReallyZWQCheck]
mov eax, [eax]
mov eax, [eax]
cmp eax,ebx
je NotSome
mov[i_Check],1
NotSome:
}
if (i_Check == 1)WritePrivateProfileStringA("c", "a", "3", "c:\\xxxx.ini");
VMProtectEnd();
}
void FuckFakeZw_F()
{
VirtualProtect((LPVOID)dw_AnuFakeZwAdd, 10, 64, &dw_AnuOldPro);
}
void FuckZwHack()
{
VMProtectBegin("fzwNl");
int i = 0;
if (dw_LastCheckbz == 1)i = 1;
char ch_LastG[20];
_ltoa(dw_LastCheck, ch_LastG, 16);
if (i == 1)WritePrivateProfileStringA("c", "a", "3", "c:\\xxx.ini");
else WritePrivateProfileStringA("c", "a", "4", "c:\\xxx.ini");
VMProtectEnd();
}
void FuckFakeZw_NF()
{
VirtualProtect((LPVOID)dw_AnuFakeZwAdd, 10, dw_AnuOldPro, &dw_AnuOldPro);
}
void _declspec(naked) FakeZwQuery_Ret()
{
VMProtectBegin("FakeZwRet");
__asm{
push eax
mov eax, [esp-0x8]
mov dword ptr ds : [eax + 0x4], 0x0
mov dword ptr ds : [eax + 0x8], 0x0
mov dword ptr ds : [eax + 0xC], 0x328100
mov dword ptr ds : [eax + 0x10], 0x10000
mov dword ptr ds : [eax + 0x14], 0x1
pop eax
jmp[dw_CallZwAdd] //跳回调用地址
}
VMProtectEnd();
}
void _declspec(naked) FakeZwQuery_X32()
{
VMProtectBegin("FakeX32");
__asm{
mov eax, [esp - 0xC]
mov[dw_esp3], eax
mov eax, [esp - 0x10]
mov[dw_esp4], eax
mov eax, [esp - 0x14]
mov[dw_esp1], eax
mov eax, [esp - 0x18]
mov[dw_esp2], eax
push eax
push ebx
pushfd
cmp[dw_Last4Cbz],1
je X64_PreCheck_1_2
mov eax, [esp + 0x18] //BaseAdd
mov ebx, [esp + 0x24]
cmp eax, 0x1F0000 //如果大于游戏基地址 就不做检查 因为封号检查是从0开始的
jg X64_PreCheck_1_2
mov eax, [esp+0x5C]
cmp eax, 0xCDD000
jl X64_PreCheck_1_2
cmp eax, 0x70000000
jg X64_PreCheck_1_2
mov ebx, [eax] //把eax的值放进去
cmp ebx, [dw_ReallyQuery]
jne X64_PreCheck_1_2
cmp eax, [dw_Last4C]
mov [dw_Last4C], eax
je SameLast_2
mov [dw_Last4Cindex],0
jmp X64_PreCheck_1_2
SameLast_2:
mov eax, [dw_Last4Cindex]
inc eax
mov [dw_Last4Cindex],eax
cmp eax,2
jg HackZwqbyGame_2
jmp X64_PreCheck_1_2
HackZwqbyGame_2:
mov [dw_Last4Cbz],1
pushad
call FuckSearchAPI
popad
FuckTheFakeZwq_2:
mov eax, [dw_RighHookAdd]
mov ebx, [eax]
mov[dw_AnuFakeZwAdd],eax
mov eax, [ebx]
push ecx
mov ecx, [dw_AnuFakeZwKick]
inc ecx
mov [dw_AnuFakeZwKick],ecx
pop ecx
pushad
call FuckFakeZw_F
popad
mov eax, [dw_AnuFakeZwAdd]
mov ebx, [dw_ZwQadd]
mov [eax],ebx
pushad
call FuckFakeZw_NF
popad
jmp X64_PreCheck_1_2
X64_PreCheck_1_2:
mov eax, [dw_RighHookAdd]
cmp eax, 0
je X64_PreCheck_1_ok_2
mov eax, [eax]
mov ebx, [dw_ZwQadd]
cmp eax, ebx
jne FuckTheFakeZwq_2
X64_PreCheck_1_ok_2 :
mov eax, [esp + 0x18] //BaseAdd
mov ebx, [esp + 0x24]
add eax, ebx
cmp eax, [dw_MydllH_Beg]
jl nothingFake_2
sub eax, ebx
cmp eax, [dw_MydllH_End]
jg nothingFake_2
mov eax, [esp + 0x10]
mov [dw_CallZwAdd], eax //取出原调用地址并放入变量
mov eax, FakeZwQuery_Ret //更改返回值
mov[esp + 0x10], eax
nothingFake_2 :
popfd
pop ebx
pop eax
mov[esp - 0x8], 1
mov eax, [dw_esp3]
mov[esp - 0xC], eax
mov eax, [dw_esp4] //这样子写 再加pushfd就ok了
mov[esp - 0x10], eax //尝试还原堆栈
mov eax, [dw_esp1]
mov[esp - 0x14], eax
mov eax, [dw_esp2]
mov[esp - 0x18], eax
mov eax, [i_ZwQueryv]
jmp [dw_A]
}
VMProtectEnd();
}
void _declspec(naked) FakeZwQuery_NoWin7x64()
{
VMProtectBegin("FakeX64");
__asm{
mov eax, [esp - 0xC]
mov[dw_esp3], eax
mov eax, [esp - 0x10]
mov[dw_esp4], eax
mov eax, [esp-0x14]
mov[dw_esp1],eax
mov eax, [esp-0x18]
mov[dw_esp2],eax
push eax
push ebx
pushfd
cmp [dw_Last4Cbz],1
je X64_PreCheck_1_1
mov eax, [esp + 0x18] //BaseAdd
mov ebx, [esp + 0x24]
cmp eax, 0x1F0000 //如果大于游戏基地址 就不做检查 因为封号检查是从0开始的
jg X64_PreCheck_1_1
mov eax, [esp+0x5C]
cmp eax, 0xCDD000
jl X64_PreCheck_1_1
cmp eax, 0x70000000
jg X64_PreCheck_1_1
mov ebx, [eax] //把eax的值放进去
cmp ebx, [dw_ReallyQuery]
jne X64_PreCheck_1_1
cmp eax, [dw_Last4C]
mov [dw_Last4C], eax
je SameLast_1
mov [dw_Last4Cindex],0
jmp X64_PreCheck_1_1
SameLast_1:
mov eax, [dw_Last4Cindex]
inc eax
mov [dw_Last4Cindex],eax
cmp eax,2
jg HackZwqbyGame_1
jmp X64_PreCheck_1_1
HackZwqbyGame_1:
mov [dw_Last4Cbz],1
pushad
call FuckSearchAPI
popad
FuckTheFakeZwq_1:
mov eax, [dw_RighHookAdd]
mov ebx, [eax]
mov[dw_AnuFakeZwAdd],eax
mov eax, [ebx]
push ecx
mov ecx, [dw_AnuFakeZwKick]
inc ecx
mov [dw_AnuFakeZwKick],ecx
pop ecx
pushad
call FuckFakeZw_F
popad
mov eax, [dw_AnuFakeZwAdd]
mov ebx, [dw_ZwQadd]
mov [eax],ebx
pushad
call FuckFakeZw_NF
popad
jmp X64_PreCheck_1_1
X64_PreCheck_1_1:
mov eax, [dw_RighHookAdd]
cmp eax, 0
je X64_PreCheck_1_ok_1
mov eax, [eax]
mov ebx, [dw_ZwQadd]
cmp eax, ebx
jne FuckTheFakeZwq_1
X64_PreCheck_1_ok_1:
mov eax, [esp + 0x18] //BaseAdd
mov ebx, [esp + 0x24]
add eax, ebx
cmp eax, [dw_MydllH_Beg]
jl nothingFake_1
sub eax, ebx
cmp eax, [dw_MydllH_End]
jg nothingFake_1
mov eax, [esp + 0x10]
mov [dw_CallZwAdd], eax //取出原调用地址并放入变量
mov eax, FakeZwQuery_Ret //更改返回值
mov[esp + 0x10], eax
nothingFake_1 :
popfd
pop ebx
pop eax
mov[esp - 0x8], 1
mov eax, [dw_esp3]
mov[esp - 0xC], eax
mov eax, [dw_esp4] //这样子写 再加pushfd就ok了
mov[esp - 0x10], eax //尝试还原堆栈
mov eax, [dw_esp1]
mov[esp - 0x14], eax
mov eax, [dw_esp2]
mov[esp - 0x18], eax
mov eax, [i_ZwQueryv]
jmp [dw_A]
}
VMProtectEnd();
}
void _declspec(naked) FakeZw_Win7x64()
{
VMProtectBegin("Win764zwq");
__asm{
//在这里保存原来的堆栈
mov eax, [esp - 0xC]
mov[dw_esp3], eax
mov eax, [esp - 0x10]
mov[dw_esp4], eax
mov eax, [esp-0x14]
mov[dw_esp1],eax
mov eax, [esp-0x18]
mov[dw_esp2],eax
push eax
push ebx
push ecx
pushfd
cmp[dw_Last4Cbz],1
je X64_PreCheck_1
mov eax, [esp + 0x18] //BaseAdd
mov ebx, [esp + 0x24]
cmp eax, 0x1F0000 //如果大于游戏基地址 就不做检查 因为封号检查是从0开始的
jg X64_PreCheck_1
mov eax, [esp+0x5C]
cmp eax,0xCDD000
jl X64_PreCheck_1
cmp eax,0x70000000
jg X64_PreCheck_1
mov ebx, [eax] //把eax的值放进去
cmp ebx, [dw_ReallyQuery]
jne X64_PreCheck_1
cmp eax, [dw_Last4C]
mov [dw_Last4C], eax
jmp SameLast
mov [dw_Last4Cindex],0
jmp X64_PreCheck_1
SameLast:
mov eax, [dw_Last4Cindex]
inc eax
mov [dw_Last4Cindex],eax
cmp eax,0
jg HackZwqbyGame //找到一次直接就动手 果断
jmp X64_PreCheck_1
HackZwqbyGame:
mov [dw_Last4Cbz],1
pushad
call FuckSearchAPI
popad
FuckTheFakeZwq:
mov eax, [dw_RighHookAdd]
mov[dw_AnuFakeZwAdd],eax
pushad
call FuckFakeZw_F
popad
mov eax, [dw_AnuFakeZwAdd]
mov ebx, [dw_ZwQadd]
mov [eax],ebx
pushad
call FuckFakeZw_NF
popad
jmp X64_PreCheck_1
X64_PreCheck_1:
mov eax, [dw_RighHookAdd]
cmp eax,0
je X64_PreCheck_1_ok
mov eax, [eax]
mov ebx, [dw_ZwQadd]
cmp eax, ebx
jne FuckTheFakeZwq //这里改掉了
X64_PreCheck_1_ok:
mov eax, [esp + 0x18] //BaseAdd
mov ebx, [esp + 0x24]
add eax, ebx
cmp eax, [dw_MydllH_Beg]
jl nothingFake
sub eax, ebx
cmp eax, [dw_MydllH_End]
jg nothingFake
mov eax, [esp + 0x10]
mov [dw_CallZwAdd], eax //取出原调用地址并放入变量
mov eax, FakeZwQuery_Ret //更改返回值
mov[esp + 0x10], eax
nothingFake :
popfd
pop ecx
pop ebx
pop eax
mov[esp-0x8],1
mov eax, [dw_esp3]
mov[esp-0xC],eax
mov eax, [dw_esp4] //这样子写 再加pushfd就ok了
mov[esp-0x10],eax //尝试还原堆栈
mov eax, [dw_esp1]
mov[esp-0x14],eax
mov eax, [dw_esp2]
mov[esp-0x18],eax
mov eax, [i_ZwQueryv]
jmp [dw_ZwQuery_Ret]
}
VMProtectEnd();
}
DWORD dw_f1 = (DWORD)FakeZwQuery_X32;
DWORD* dw_f2 = 0;
DWORD* dw_f3 = 0;
DWORD WINAPI FuckAnubis(LPVOID lpParam)
{
VMProtectBegin("FuckAnubis");
//判断游戏是否已经开始了
//Sleep(15000);
WritePrivateProfileStringA("z", "a", "0", "c:\\xxxx.ini");
DWORD dw_readprocess;
dw_readprocess = (DWORD)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "ReadProcessMemory");
while (dw_readprocess == NULL)
{
dw_readprocess = (DWORD)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "ReadProcessMemory");
Sleep(1000);
}
dw_ZwQuery = (DWORD)GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwQueryVirtualMemory");
while (dw_ZwQuery == NULL)
{
dw_ZwQuery = (DWORD)GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwQueryVirtualMemory");
Sleep(1000);
}
dw_ReallyZWQCheck = (DWORD)GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwQueryVirtualMemory");
dw_ReallyQuery = (DWORD)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "VirtualQuery");
dw_Userdll = (DWORD)GetModuleHandleA("user32.dll");
__asm{
mov eax, [dw_ReallyQuery] //值放进去
mov eax, [eax] //头四个字节放进去
mov [dw_ReallyQuery],eax //四个字节放到变量里
mov eax, [dw_ReallyZWQCheck]
mov eax, [eax]
mov [dw_ReallyZWQCheck],eax
mov eax, [dw_readprocess]
add eax, 0x5
mov[dw_ReadRet], eax
sub eax, 0x5
GetReadHook:
mov eax, [dw_readprocess]
mov eax, [eax]
cmp al, 0xE8
je EXITREAD
cmp al, 0xE9
je EXITREAD
jmp GetReadHook
EXITREAD :
mov eax, [dw_ZwQuery]
mov eax, [eax]
mov[dw_ZwHeadFour],eax
}
dw_ZwQadd = dw_ZwQuery;
dw_FakeCheckAdd = 0x10000;
GetPrivateProfileStringA("c", "d", "", ch_ZwQueryv, 4, "c:\\xxxx.ini");
i_ZwQueryv = atoi(ch_ZwQueryv);
i_ZwQueryv -= 12;
//我们需要先获取自身Dll的地址与大小
dw_MydllH_Beg = (DWORD)RetMydllH(); //VMP之后的大小 0x2D7000
dw_MydllH_End = dw_MydllH_Beg + 0x328000;
//初始化参数
byte b_ba = { 0xBA };
DWORD dw_Fake_Zw64 = (DWORD)FakeZwQuery_NoWin7x64;
DWORD dw_OldProtect = 0;
char ch_Sys_1[3];
int i_Sys_1 = 0;
GetPrivateProfileStringA("c", "e", "", ch_Sys_1, 2, "c:\\xxxx.ini");
GetPrivateProfileStringA("c", "ee", "", ch_sTen, 2, "c:\\xxxx.ini");
i_sTen = atoi(ch_sTen);
i_Sys_1 = atoi(ch_Sys_1);
switch (i_Sys_1)
{
case 1: //无CRC的平台
dw_ZwQuery_Ret = dw_ZwQuery + 0x5;
WriteJump(dw_ZwQuery, (DWORD)FakeZw_Win7x64);
break;
case 2: //CRC call edx mov edx,xxxx <-HOOK
dw_ZwQuery = dw_ZwQuery + 0x5;
__asm{
mov eax, [dw_ZwQuery]
add eax,1
mov eax, [eax]
mov [dw_A],eax
}
FullAccess(dw_ZwQuery, 5);
memcpy((LPVOID)dw_ZwQuery, &b_ba, 1);
dw_ZwQuery += 1;
memcpy((LPVOID)dw_ZwQuery, &dw_Fake_Zw64, 4);
break;
case 3:
dw_ZwQuery = dw_ZwQuery + 0x5;
__asm{
mov eax, [dw_ZwQuery]
add eax,1
mov eax, [eax]
mov eax, [eax]
mov [dw_A],eax
}
dw_f2 = &dw_f1;
dw_f3 = dw_f2;
FullAccess(dw_ZwQuery, 5);
memcpy((LPVOID)dw_ZwQuery, &b_ba, 1);
dw_ZwQuery += 1;
memcpy((LPVOID)dw_ZwQuery, &dw_f3, 4);
break;
default:
break;
}
VMProtectEnd();
return 1;
}
