很有技术含量,为了整理精华9方便些,我将DOC文章转帖到论坛上来:
标 题: 【原创】WoW's一点小诡计简单分析
作 者: foxabu
时 间: 2007-06-07,15:42
链 接: http://bbs.pediy.com/showthread.php?t=45935
不说大家都知道什么游戏.不过我还是以US服务器为例来讨论问题.
前两天我做了一个软件 照常规方式OpenProcess Read/WriteProcessMemory.然后很不幸我的程序报错,给我说System Error : 5 On OpenProcess..晕,我很确信我不可能代码有问题,因为这个模板我已经用了多次了.当时我还很郁闷.明明OD可以调试啊,不像是ANTI-DEBUG之类的啊,而且任务管理器也可以结束这个进程..郁闷的半天.而用我用Cheat Engine 打开也提示 OpenProcess failed!.这下晕了.我首先想到可能是全局钩子.迅速打开OD 记载程序查找模块,我一个一个的眼睛弄得圆圆的也没有找到半个DLL的痕迹,一下子懵了,因为在Vista中默认是没有权限加载驱动的.这是怎么的呢?但是还是拿出IceSword这个尚方宝剑来弄了半天检查了一下SSTD.结果很令人失望.啥都没有.这下我就奇怪了,在相关可能HOOK之类的API下断点,也没见程序断下…
突然想起那天打开IDA的时候不小心看到了几个导入函数.会不会是这个呢?
于是我在所有的这几个的函数参考下断点,然后顺利来到
006E21A0 /$ 55 push ebp ; Lock_AccessProcess
006E21A1 |. 8BEC mov ebp,esp
006E21A3 |. 81EC 20020000 sub esp,220
006E21A9 |. A1 88C48000 mov eax,dword ptr ds:[80C488]
006E21AE |. 33C5 xor eax,ebp
006E21B0 |. 8945 FC mov [local.1],eax
006E21B3 |. 53 push ebx
006E21B4 |. 33DB xor ebx,ebx
006E21B6 |. 56 push esi
006E21B7 |. 57 push edi
006E21B8 |. 889D F4FDFFFF mov byte ptr ss:[ebp-20C],bl
006E21BE |. 889D F5FDFFFF mov byte ptr ss:[ebp-20B],bl
006E21C4 |. 889D F6FDFFFF mov byte ptr ss:[ebp-20A],bl
006E21CA |. 889D F7FDFFFF mov byte ptr ss:[ebp-209],bl
006E21D0 |. 889D F8FDFFFF mov byte ptr ss:[ebp-208],bl
006E21D6 |. C685 F9FDFFFF 01 mov byte ptr ss:[ebp-207],1
006E21DD |. FF15 5CA17900 call dword ptr ds:[<&KERNEL32.GetCurrentP>; [GetCurrentProcess
006E21E3 |. 8BF0 mov esi,eax
006E21E5 |. 8D85 E8FDFFFF lea eax,[local.134]
006E21EB |. 50 push eax
006E21EC |. 53 push ebx
006E21ED |. 53 push ebx
006E21EE |. 53 push ebx
006E21EF |. 53 push ebx
006E21F0 |. 53 push ebx
006E21F1 |. 53 push ebx
006E21F2 |. 53 push ebx
006E21F3 |. 53 push ebx
006E21F4 |. 6A 01 push 1
006E21F6 |. 8D8D F4FDFFFF lea ecx,[local.131]
006E21FC |. 51 push ecx
006E21FD |. 89B5 E0FDFFFF mov [local.136],esi
006E2203 |. 899D E8FDFFFF mov [local.134],ebx
006E2209 |. 899D ECFDFFFF mov [local.133],ebx
006E220F |. 899D E4FDFFFF mov [local.135],ebx
006E2215 |. 889D F3FDFFFF mov byte ptr ss:[ebp-20D],bl
006E221B |. FF15 38A07900 call dword ptr ds:[<&ADVAPI32.AllocateAnd>; ADVAPI32.AllocateAndInitializeSid
006E2221 |. 85C0 test eax,eax
006E2223 |. 0F84 E2000000 je WoW.006E230B
006E2229 |. 8D95 ECFDFFFF lea edx,[local.133]
006E222F |. 52 push edx ; /phToken
006E2230 |. 6A 08 push 8 ; |DesiredAccess = TOKEN_QUERY
006E2232 |. 56 push esi ; |hProcess
006E2233 |. FF15 3CA07900 call dword ptr ds:[<&ADVAPI32.OpenProcess>; \OpenProcessToken
006E2239 |. 85C0 test eax,eax
006E223B |. 0F84 CA000000 je WoW.006E230B
006E2241 |. 8B8D ECFDFFFF mov ecx,[local.133]
006E2247 |. 8D85 E4FDFFFF lea eax,[local.135]
006E224D |. 50 push eax ; /pRetLen
006E224E |. 53 push ebx ; |BufSize => 0
006E224F |. 53 push ebx ; |Buffer => NULL
006E2250 |. 6A 01 push 1 ; |InfoClass = TokenUser
006E2252 |. 51 push ecx ; |hToken
006E2253 |. FF15 00A07900 call dword ptr ds:[<&ADVAPI32.GetTokenInf>; \GetTokenInformation
006E2259 |. 8BB5 E4FDFFFF mov esi,[local.135]
006E225F |. 81FE 00040000 cmp esi,400
006E2265 |. 0F87 A0000000 ja WoW.006E230B
006E226B |. 8BC6 mov eax,esi
006E226D |. E8 9E7CD2FF call <WoW.__alloca_probe_16>
006E2272 |. 8B85 ECFDFFFF mov eax,[local.133]
006E2278 |. 8BFC mov edi,esp
006E227A |. 8D95 E4FDFFFF lea edx,[local.135]
006E2280 |. 52 push edx ; /pRetLen
006E2281 |. 56 push esi ; |BufSize
006E2282 |. 57 push edi ; |Buffer
006E2283 |. 6A 01 push 1 ; |InfoClass = TokenUser
006E2285 |. 50 push eax ; |hToken
006E2286 |. FF15 00A07900 call dword ptr ds:[<&ADVAPI32.GetTokenInf>; \GetTokenInformation
006E228C |. 85C0 test eax,eax
006E228E |. 74 7B je short WoW.006E230B
006E2290 |. 6A 02 push 2
006E2292 |. 68 00020000 push 200
006E2297 |. 8D8D FCFDFFFF lea ecx,[local.129]
006E229D |. 51 push ecx
006E229E |. FF15 44A07900 call dword ptr ds:[<&ADVAPI32.InitializeA>; ADVAPI32.InitializeAcl
006E22A4 |. 85C0 test eax,eax
006E22A6 |. 74 63 je short WoW.006E230B
006E22A8 |. 8B95 E8FDFFFF mov edx,[local.134]
006E22AE |. 52 push edx
006E22AF |. 68 FA000000 push 0FA
006E22B4 |. 6A 02 push 2
006E22B6 |. 8D85 FCFDFFFF lea eax,[local.129]
006E22BC |. 50 push eax
006E22BD |. FF15 40A07900 call dword ptr ds:[<&ADVAPI32.AddAccessDe>; ADVAPI32.AddAccessDeniedAce
006E22C3 |. 85C0 test eax,eax
006E22C5 |. 74 44 je short WoW.006E230B
006E22C7 |. 8B0F mov ecx,dword ptr ds:[edi]
006E22C9 |. 51 push ecx
006E22CA |. 68 01071000 push 100701
006E22CF |. 6A 02 push 2
006E22D1 |. 8D95 FCFDFFFF lea edx,[local.129]
006E22D7 |. 52 push edx
006E22D8 |. FF15 48A07900 call dword ptr ds:[<&ADVAPI32.AddAccessAl>; ADVAPI32.AddAccessAllowedAce
006E22DE |. 85C0 test eax,eax
006E22E0 |. 74 29 je short WoW.006E230B
006E22E2 |. 8B8D E0FDFFFF mov ecx,[local.136]
006E22E8 |. 53 push ebx
006E22E9 |. 8D85 FCFDFFFF lea eax,[local.129]
006E22EF |. 50 push eax
006E22F0 |. 53 push ebx
006E22F1 |. 53 push ebx
006E22F2 |. 68 04000080 push 80000004
006E22F7 |. 6A 06 push 6
006E22F9 |. 51 push ecx
006E22FA |. FF15 04A07900 call dword ptr ds:[<&ADVAPI32.SetSecurity>; ADVAPI32.SetSecurityInfo
006E2300 |. 85C0 test eax,eax
006E2302 |. 75 07 jnz short WoW.006E230B
006E2304 |. C685 F3FDFFFF 01 mov byte ptr ss:[ebp-20D],1
006E230B |> 8B85 ECFDFFFF mov eax,[local.133]
006E2311 |. 3BC3 cmp eax,ebx
006E2313 |. 74 07 je short WoW.006E231C
006E2315 |. 50 push eax ; /hObject
006E2316 |. FF15 74A27900 call dword ptr ds:[<&KERNEL32.CloseHandle>; \CloseHandle
006E231C |> 8B85 E8FDFFFF mov eax,[local.134]
006E2322 |. 3BC3 cmp eax,ebx
006E2324 |. 74 07 je short WoW.006E232D
006E2326 |. 50 push eax ; /pSID
006E2327 |. FF15 08A07900 call dword ptr ds:[<&ADVAPI32.FreeSid>] ; \FreeSid
006E232D |> 8A85 F3FDFFFF mov al,byte ptr ss:[ebp-20D]
006E2333 |. 8DA5 D4FDFFFF lea esp,[local.139]
006E2339 |. 5F pop edi
006E233A |. 5E pop esi
006E233B |. 5B pop ebx
006E233C |. 8B4D FC mov ecx,[local.1]
006E233F |. 33CD xor ecx,ebp
006E2341 |. E8 946FD2FF call WoW.004092DA
006E2346 |. 8BE5 mov esp,ebp
006E2348 |. 5D pop ebp
006E2349 \. C3 retn
经过测试发现只要经过了这个过程,就无法用程序OpenProcess打开.这种进程反外挂的方法还有点特别.至少本人觉得是.所以把它写成文章给大家分享:
这段代码很标准,应该是VC7或者VC7.1生成的
我把它简单逆向:
BOOL Lock_CurrentProcess()
{
HANDLE hProcess = ::GetCurrentProcess();
SID_IDENTIFIER_AUTHORITY sia = SECURITY_WORLD_SID_AUTHORITY;
PSID pSid;
BOOL bSus = FALSE;
bSus = ::AllocateAndInitializeSid(&sia,1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&pSid);
if(!bSus) goto Cleanup;
HANDLE hToken;
bSus = ::OpenProcessToken(hProcess,TOKEN_QUERY,&hToken);
if(!bSus) goto Cleanup;
DWORD dwReturnLength;
::GetTokenInformation(hToken,TokenUser,NULL,NULL,&dwReturnLength);
if(dwReturnLength > 0x400) goto Cleanup;
LPVOID TokenInformation;
TokenInformation = ::LocalAlloc(LPTR,0x400);//这里就引用SDK的函数不引用CRT的了
DWORD dw;
bSus = ::GetTokenInformation(hToken,TokenUser,TokenInformation,0x400,&dw);
if(!bSus) goto Cleanup;
PTOKEN_USER pTokenUser = (PTOKEN_USER)TokenInformation;
BYTE Buf[0x200];
PACL pAcl = (PACL)&Buf;
bSus = ::InitializeAcl(pAcl,1024,ACL_REVISION);
if(!bSus) goto Cleanup;
bSus = ::AddAccessDeniedAce(pAcl,ACL_REVISION,0x000000FA,pSid);
if(!bSus) goto Cleanup;
bSus = ::AddAccessAllowedAce(pAcl,ACL_REVISION,0x00100701,pTokenUser->User.Sid);
if(!bSus) goto Cleanup;
if(::SetSecurityInfo(hProcess,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,NULL,NULL,pAcl,NULL) == 0)
bSus = TRUE;
Cleanup:
if(hProcess != NULL)
::CloseHandle(hProcess);
if(pSid != NULL)
::FreeSid(pSid);
return bSus;
}
这段代码就可以锁住其他进程打开本进程,当然也就防止了注入,和读写内存.
来段测试代码吧:
void TestFunc()
{
BOOL bSus;
HANDLE hProcess;
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,FALSE,GetCurrentProcessId());
printf("Before Call Lock_AccessProcess OpenProcess Returns : 0x%08X \r\n",hProcess);
CloseHandle(hProcess);
bSus = ::Lock_CurrentProcess();
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,FALSE,GetCurrentProcessId());
printf("After Call Lock_AccessProcess OpenProcess Returns : 0x%08X ,System Error Code :%d",hProcess,GetLastError());
CloseHandle(hProcess);
system("PAUSE");
}
执行后控制台输出:
Before Call Lock_AccessProcess OpenProcess Returns : 0x00000034
After Call Lock_AccessProcess OpenProcess Returns : 0x00000000 ,System Error Code :5请按任意键继续. . .
我们大家都知道 Code : 5
ERROR_ACCESS_DENIED Access is denied.
5
这一点就连WINDOWS的任务管理器也无法躲过:
看到没有哈 用户名根本出不来,甚至你可以更绝点Denied ALL ACCESS(0xFFFFFFFF)就连结束都不可能了哈.
既然代码给出了还是论一下代码,因为我这个是逆向,就完全按照代码框架来写的其实.
::AllocateAndInitializeSid 可以换成 :: InitializeSid .因为我们并不需要初始化子Sid.
另外.
bSus = ::AddAccessDeniedAce(pAcl,ACL_REVISION,0x000000FA,pSid);
if(!bSus) goto Cleanup;
bSus = ::AddAccessAllowedAce(pAcl,ACL_REVISION,0x00100701,pTokenUser->User.Sid);
实际上只需要下面的一句,或者干脆把它去掉,因为如果不添加Ace默认就是没有权限.既然这样上面的那句话AllocateAndInitializeSid 也可以省掉,也似乎有些多余.这里可能有别的什么原因,不明,有知道的可以指点一下.