看流星社区

 找回密码
 注册账号
查看: 2516|回复: 0

妙不可言――挂接ExitWindowsEx

[复制链接]

该用户从未签到

发表于 2013-5-24 08:52:19 | 显示全部楼层 |阅读模式
随着安全意识的不断提高,许多软件都增强的自我保护性,结束其进程时将会调用ExitWindowsEx函数关机或者重启。这种技术在收费管理系统、病毒木马、加壳软件、反破解领域里很常见,因而采用APIHOOK技术挂接ExitWindowsEx函数使其失效,对与我们查杀病毒以及软件破解是很有用的。当然还能运用它免费上网呢!不可思议吧?现在许多收费软件都采取会员制,下机时点结帐下机按钮后,客户端就发送数据报给主机,告知用户已下机从而停止记费,同时重新启动或关闭计算机。我们挂接ExitWindowsEx后就可以让机子不重启,怎么样?免费上网还可以这么搞,嘿嘿,你没想到吧?(俺正得意,突然面前飞来小李飞刀,我闪,好险啦!)

记得去年第12期的黑防上有篇关于APIHOOK的文章, 那篇所采用的方法是陷阱法(改写内存地址jmp法),我这里就用另外一种方法吧――改写IAT(引入表)法。这种方法的优点是较稳定,不要担心线程同步的问题。
APIHOOK技术应用广泛,常用于屏幕取词、网络防火墙、病毒木马、加壳软件、串口红外通信、游戏智辅、Internet通信等领域。HOOK的中文意思就是钩子,APIHOOK就是钩住API,对API进行预处理,先执行我们的函数。这类思路是不是在我们中华民族文化瑰宝《三十六计》中有所体现啦!俺们先辈实在太伟大了,敬佩中。其实HOOK是黑客领域里的一种不可或缺的思想。是不是有点跑题了?言归正传。

改写IAT表法实现APIHOOK的思路如下:根据PE文件格式穷举模块中的image_impot_desciptor引入函数数组, 检查进程空间里是否有要HOOK的API的所在的DLL,如果有则通过WiteProcessMemory、VirtualProtect等函数改写IAT中的目标API函数地址,将其改为我们自定义函数的地址。由于地址不能跨进程引用,所以我们可以使用Windows消息钩子将我们APIHOOK所在的DLL注入到其他进程里, 为了取得较好的效果,推荐使用WH_GETMESSAGE类性的钩子。


现在就来解析核心代码:
void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName, PROC pfnOriginApiAddress, PROC pfnDummyFuncAddress, HMODULE hModCallerModule)
//对于挂接ExitWindowsEx函数而言,pszCalleeModuleName为user32.dll, pfnOriginApiAddress为ExitWindowsEx,pfnDummyFuncAddress 为MyExitWindowsEx
{
ULONG size;

//获取指向PE文件中的Import中IMAGE_DIRECTORY_DESCRIPTOR数组的指针

PIMAGE_IMPORT_DESCRIPTOR pImportDesc=
(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hModCallerModule,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);
//查找记录,查找是否存在目标API函数ExitWindwosEx所在的user32.dll
for (;pImportDesc->Name;pImportDesc++)
{
LPSTR pszDllName = (LPSTR)((PBYTE)hModCallerModule+pImportDesc->Name);
if (lstrcmpiA(pszDllName,pszCalleeModuleName) == 0)
break;
}
//寻找我们所要HOOK的ExitWindwosEx函数
PIMAGE_THUNK_DATA pThunk =
(PIMAGE_THUNK_DATA)((PBYTE)hModCallerModule+pImportDesc->FirstThunk);
for (;pThunk->u1.Function;pThunk++)
{
//ppfn记录了与IAT项相应的函数的地址
PROC * ppfn= (PROC *)&pThunk->u1.Function;
if (*ppfn == pfnOriginApiAddress)
{
//如果地址相同,就说明找到了我们要HOOK的函数,进行改写,将其指向我们所
定义的函数
WriteProcessMemory(GetCurrentProcess(),ppfn,&(pfnDummyFuncAddress),
sizeof(pfnDummyFuncAddress),NULL);
return;
}
}
}


若想HOOK所有模块对目标API函数的调用,则需要使用ToolHelp函数枚举所有模块,然后逐一调用HookOneAPI函数。关键代码如下:
BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
{
if (hModCallerModule == NULL)
{
MEMORY_BASIC_INFORMATION mInfo;
HMODULE hModHookDLL;
HANDLE hSnapshot;
MODULEENTRY32 me = {sizeof(MODULEENTRY32)};
//MODULEENTRY32:存放被指定进程所应用的模块信息的结构
VirtualQuery(HookOneAPI,&mInfo,sizeof(mInfo));
hModHookDLL=(HMODULE)mInfo.AllocationBase;
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0);
BOOL bOk = Module32First(hSnapshot,&me);
while (bOk)
{
if (me.hModule != hModHookDLL)
{
hModCallerModule = me.hModule;//赋值
//对每一个模块进行HOOK
HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,
pfnDummyFuncAddress,hModCallerModule);
}
bOk = Module32Next(hSnapshot,&me);
}
return TRUE;
}
}


接着就要调用调用SetWindowsHookEx来安装WH_GETMESSAGE 类型的钩子把APIHOOK的DLL映射到其它进程空间里:SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)GetMsgProc,hmodDll,dwThreadId)。 GetMsgProc函数里只要写上return CallNextHookEx(hHook,code,wParam,lParam);即可,实现循环。


现在就剩下自定义ExitWindowsEx函数了,我们只需注意参数格式和原函数一样即可,自定义的MyExitWindowsEx函数什么都不做,这样就实现的取消关机的功能了。
另外还有一点要注意一下,对于winlogon.exe,我们要提升权限至调试权限,代码如下:
if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
{
LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid);
tp.PrivilegeCount=1;
tp.Privileges[0].Luid=luid;
tp.Privileges[0].Attributes=bUp?SE_PRIVILEGE_ENABLED:0;
if(!AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL))
{
MessageBox(NULL,"提升权限失败!","",0);
return;
}
}


整个框架就是这样了,由于篇幅原因,具体的不再细说了。
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-5-16 00:57

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表