实践1
背景
某软件A,在非全屏显示时带有常规菜单,在全屏下没有常规菜单,但是有顶部工具条,工具条上有菜单和按钮。对于全屏和非全屏的切换可以通过菜单,也可以通过快捷键ctrl + alt + enter进行。
需求
需要将菜单和工具条去除,同时将切换全屏/非全屏快捷键修改为ctrl + alt + shift。
调研
当拿到这个需求的时候,直观上感觉需要逆向,大概也知道一些逆行工具,比如IDA Pro、OllyDbg、x64dbg之类的,经过调研得知:
- IDA Pro:PE文件静态分析工具,也可以进行调试;
- OllyDbg:只能调试32位进程;
- x64dbg:调试64位进程;
- x32dbg:调试32位进程。
IDA Pro
IDA Pro 是一款功能强大的反汇编和反编译软件,由意大利公司 Hex-Rays 开发。它主要用于分析和理解应用程序的代码和逻辑,支持多种平台和架构,包括 Windows、Linux、macOS、ARM、x86 等。IDA Pro 在反向工程和安全研究领域被广泛应用,常用于恶意软件分析、漏洞分析、软件开发、操作系统内核分析等方面。
主要功能包括:
- 反汇编功能:将目标程序的机器代码转换为可读性更高的汇编代码,帮助用户分析程序的代码结构和逻辑。
- 反编译功能:通过 Hex-Rays Decompiler 插件,将汇编代码转换为类似 C 语言的高级语言代码,使代码更易于理解和分析。
- 调试功能:支持与多种调试器集成,用户可以在程序运行时查看变量、堆栈、寄存器等信息,并设置断点、单步执行等。
- 插件支持:用户可以通过插件扩展 IDA Pro 的功能,例如自动化分析、生成脚本等。
- 数据库功能:生成和维护程序的数据库,存储函数、变量、注释等信息,便于快速访问和分析。
- 跨平台支持:支持多种操作系统和架构,用户可以在不同平台上使用 IDA Pro 进行反汇编和反编译工作。
应用场景:
• 逆向工程 :分析二进制文件,了解程序的工作原理和逻辑。
• 恶意软件分析 :通过反汇编和调试,分析可疑文件的行为和潜在威胁。
• 漏洞挖掘 :发现程序中的安全漏洞和潜在风险。
• 软件开发:帮助开发者调试和分析编译后的二进制文件。
解决过程
观察这个软件的安装目录,发现有很多QT的Dll,用IDA打开该软件后观察导入表Imports和函数调用,发现确实UI是用QT做的。
- 去除常规菜单
QT菜单相关的函数有:
cpp
// 创建菜单栏
QMenuBar *menuBar = new QMenuBar(this);
QMenu *fileMenu = menuBar->addMenu("&File");
// 添加菜单项
QAction *newAction = fileMenu->addAction("&New");
QAction *openAction = fileMenu->addAction("&Open");
// 获取主窗口的菜单
QMebuBar* menuBar = QMainWindow::menuBar()
于是在反汇编中查找上述相关函数,找到如下代码:
asm
xt:000000014xxxxE89 call cs:__imp_?menuBar@QMainWindow@@QEBAPEAVQMenuBar@@XZ ; QMainWindow::menuBar(void) // 返回主窗口的菜单menuBar,返回值放入RAX
.text:000000014xxxxE8F mov rdi, rax // 再将menuBar放入rdi
.text:000000014xxxxE92 lea rbx, [rbp+130h+var_40]
.text:000000014xxxxE99 nop dword ptr [rax+00000000h]
.text:000000014xxxxEA0
.text:000000014xxxxEA0 loc_14xxxxEA0: ; CODE XREF: sub_14xxxx4B0+A0A↓j
.text:000000014xxxxEA0 mov rdx, [rbx] // rdx存放的是addMenu函数参数
.text:000000014xxxxEA3 mov rcx, rdi // rcx存放的是menuBar,即下面函数调用的this指针(x64应用程序在传参的时候,this指针使用rcx传递)
.text:000000014xxxxEA6 call cs:__imp_?addMenu@QMenuBar@@QEAAPEAVQAction@@PEAVQMenu@@@Z ; QMenuBar::addMenu(QMenu *)
.text:000000014xxxxEAC add rbx, 8
.text:000000014xxxxEB0 lea rax, [rbp+130h+var_28]
.text:000000014xxxxEB7 cmp rbx, rax
.text:000000014xxxxEBA jnz short loc_14xxxxEA0
.text:000000014xxxxEBC mov rdx, rdi
.text:000000014xxxxEBF mov rcx, r14
.text:000000014xxxxEC2 call cs:__imp_?setMenuBar@QMainWindow@@QEAAXPEAVQMenuBar@@@Z ; QMainWindow::setMenuBar(QMenuBar *)
基于以上代码,将addMenu函数替换为nop(nop对应的硬编码是0x90),call指令有6个字节:
修改后,通过菜单Edit->Patch Program->Patched bytes 写入原文件,运行后菜单确实去掉了,但副作用是快捷键ctrl + atl + enter 也不生效了。
- 去除顶部工具条
从外观观察来看,工具条应该是一个QWidget,与菜单不同,QWidget可以调用hide、move、resize、setGeometry等函数让UI呈现出消失的效果。
-
尝试hide
实际上是去除对show函数的调用,也找到了对这个函数的调用,但是副作用也是全屏状态下快捷键生效,这个情况是无法接收的,因为非全屏下的快捷键虽然也失效了,但是仍然可以用鼠标最大化后变为全屏,而全屏状态下没有快捷键的情况下是无法用鼠标恢复的,所以这一方式不可行。
-
尝试resize
找到了对这个函数调用,如下:
如果所示:对这个工具条QWidget先调用了move(QPoint const&)又调用了resize(QSize const&),
于是很容易想到,将resize函数的参数置为0,这样部件就不可见了!
因此两个函数调用是挨着的,两个rcx都是同一个对象的this指针,因为要让部件不可见,所以我们已经不关心move函数了。
将lea rdx, [rsp+38h+arg_8] 通过修改字节,将其修改为lea rdx, [rsp+38h+arg_10],此时rdx存放的就是QSize对象的地址了,即resize函数的参数地址,然后将move替换为nop,再将xxxx2E9E3地址处的字节码改为48 C7 02 00 00 00 00 ,对应的汇编代码为(为什么不直接修改为汇编代码是因为IDA提示不让修改,只能修改bytes):
asm
mov qword ptr [rdx], 0
这样就将resize函数的QSize对象修改为了一个尺寸为0的对象,然后运行后发现还是不行!
分析后得知QWidget之前调用了setSizePolicy函数来限制最小尺寸,宽度为0显然不合法,所以先去掉了对setSizePolicy的调用。
至此还是不行,工具条仍然有一部分可见,看起来可见的部分应该不是QWidget的一部分。
- 尝试move
还是基于上图,move和resize两个函数的调用挨着,这就是一个天然的便利条件!
于是尝试将resize函数修改为move函数,修改的时候有点巧,按照如下凡是修改后就变成了move函数的地址:
然后按照前面的方法,将QPoint参数的x坐标置为-1000,移动到一个不可见的位置。
地址xxxx2E9E3处的汇编代码通过修改bytes变成:
asm
lea rdx, [rsp+38h+arg_8] // 保持不变
mov dword ptr[rdx+4], 0FFFFC18h
这样工具条就隐藏了,快捷键也没有收到影响。
-
快捷键
非全屏下的快捷键的问题,通过spy++找到窗口类名,结合窗口标题起一个后台进程用FindWindow函数找到窗口句柄,向其发送SC_MAXIMIZE消息最大化(实际是全屏),当切换为非全屏时向窗口发送模拟键盘ctrl + alt + enter按下和弹起。
-
修改界面字符串
这个比较简单,只要修改后的字符串长度不超过原字符串,修改的方式就很简单,用shift + F12让IDA列出所有字符串,然后ctrl + F找到修改的字符串,找到其调用的地方,然后修改bytes即可。
2. 实践2
背景
某软件B在某个情况下无法正常使用,会弹出一个提示框,点击确定后退出。
需求
破解这种情况。
思路
- 弹框可能是MessageBox函数
- 退出时可能是exit、TerminateProcess、ExitProcess之类的
- 找到弹框和退出的地方,将其去掉调用
问题
- IDA 静态分析的时候是不会包含动态加载的DLL
- 如果进程的检测逻辑(MessageBox和退出)不在exe中怎么办?
- 启动调试的时候,是否会显示dll的反汇编代码?
- 隐式加载和显式加载的dll,如果启动exe调试是否会显示其反汇编代码?
最后
该实践没有验证完就不需要验证了,所以没有继续。