今日接到一逆向需求,要求修改一个按钮的功能。
初以为是较为常见的功能,仔细看过后才发现该软件采用了自研的二级框架
不过所幸软件的安全措施较为薄弱,经历了整整一天的折腾后终于打通,便在此处留个随笔做记录。
关键函数定位
先通过拆包和pe头分析,找出可疑xml文件,查看后发现为ui文件,于是通过该文件名在ida进行查找
同时一路分析代码调用,最终定位到了以下片段:
通过对其他dll模块进行分析,最终定位到该函数名为onSavePictureFileMenuClick,位于NTCourseExt.dll中
DLL注入
通过vs创建dll项目,再通过extern “C”等标识符导出目标函数。最后生成dll
再通过StudyPE在导入表中将测试dll及相关函数注入即可。
汇编hook
dll经进程弹窗检测注入成功,但是因为UI框架是对方自研,没法用现成的API进行按钮捕获,于是只能寄希望于修改汇编的函数调用来实现功能修改。
通过在ida中的分析,我们快速在x64dbg中定位到了相关call回调代码:
编者在此处尝试通过相对地址来调用所,但因为alsr等问题导致再次打开的时候变会出现寻址错误的问题
再关闭alsr中,相同的问题因系统原因仍无法避免。于是编者又开始尝试通过IAT表检索函数入口地址再进行导入,同样由于该段的空间有限。同时对IAT表的操作存在困难,此路不通,放弃。
DLL劫持与函数转发
既然汇编层面没有手段,那是否能通过劫持dll来做到对onSavePictureFileMenuClick()函数的重写呢?
于是编者开始研究起了DLL转发。
假设现在有a.exe与b.dll,那么dll转发就是做一个假的b.dll进去,然后充当中间商给真正的dll通信
也就变成了 a.exe b.dll(假的转发dll) c.dll(真正的b.dll改名而来)
而要进行dll转发,也就是要在假的dll中为b.dll中所有的函数建立信道,就编者目测这个dll库至少有数千条函数
于是果断放弃了人工编写,转而看向生成工具。这里编者推荐的是:SharpDllProxy
项目地址:https://github.com/Flangvik/SharpDllProxy
按照README.md使用该库,最终生成了专用于dll劫持的C语言文件:
对代码进行适应性修改后构建项目,测试生成的dll可完美充当exe与原生库的握手人,dll转发成功。
再通过微软提供的detour库编写代码实现函数的拦截重写:
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){switch (fdwReason){
case DLL_PROCESS_ATTAC:{
// 在 DLL 加载时,使用 Microsoft Detours 修改被转发的函数地址
HMODULE moduleHandle = GetModuleHandle(L”NTCourseExt.dll”);
OriginalFunctionType originalFunction = reinterpret_cast<OriginalFunctionType>(GetProcAddress(moduleHandle, “?onSavePictureFileMenuClick@NTCourseEditView@NTCourseExt@@AEAAXXZ”));
OriginalFunctionType* originalFunctionPtr = &originalFunction;
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(reinterpret_cast<void**>(originalFunctionPtr), reinterpret_cast<void*>(&onSavePictureFileMenuClick));
DetourTransactionCommit();
}
break;
case DLL_PROCESS_DETACH:{
// 在 DLL 卸载时,恢复被转发的函数地址
HMODULE moduleHandle = GetModuleHandle(L”NTCourseExt.dll”);
OriginalFunctionType originalFunction = reinterpret_cast<OriginalFunctionType>(GetProcAddress(moduleHandle, “?onSavePictureFileMenuClick@NTCourseEditView@NTCourseExt@@AEAAXXZ”));
OriginalFunctionType* originalFunctionPtr = &originalFunction;
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(reinterpret_cast<void**>(originalFunctionPtr), reinterpret_cast<void*>(&onSavePictureFileMenuClick));
DetourTransactionCommit();
}
break;
}
return TRUE;
}
再次构建dll,进行测试,功能修改成功且运行正常。项目收尾完结。