逆向环境搭建¶
逆向工具¶
静态分析工具¶
IDA Pro¶
支持Macos、Windows、Linux等平台,建议找个破解版下载
010editor¶
下载地址:010 Editor - Pro Text/Hex Editor | Edit 300+ Formats | Fast & Powerful | Reverse Engineering
文件16进制分析器,同样支持多平台
PE-bear¶
支持多平台
Ghidra¶
下载地址:GitHub - NationalSecurityAgency/ghidra: Ghidra is a software reverse engineering (SRE) framework
开源工具,支持多平台
动态调试工具¶
X64dbg¶
下载地址:x64dbg
开源工具,仅支持Windows平台
Windbg¶
下载地址:Windbg调试工具 - 官方资源与指南
微软官方工具,仅支持Windows平台,专用于调试Windows内核程序
查壳工具¶
PEID¶
仅支持Windows平台
DIE¶
下载地址:horsicq/Detect-It-Easy: Program for determining types of files for Windows, Linux and MacOS.
支持多平台
IDA Pro使用¶
我们直接用一些示例来演示
修改数据¶
这是一个简单的hello world程序,如果我们想要修改其打印的字符串,应该怎么办呢,首先我们使用IDA打开

同样先找到主程序,我们看到其汇编代码,反汇编为伪C代码(快捷键为F5)

双击字符串

定位到了aHelloWorld变量,右键Jump to operand

打开16进制页面

可以看到Hello World!对应的十六进制为4865 6c6c 6f20 576f 726c 6421,那么我们只需要替换为我们需要修改的字符串的16进制就可以了,比如我们修改为Hello Admin!,以下命令可以输出字符串对应的16进制
对应的16进制为4865 6c6c 6f20 4164 6d69 6e21

我们使用010editor修改16进制,选择从16进制粘贴,随后保存


此时再次使用ida打开,已经修改了字符串

如果要使用ida修改16进制,右键edit,编辑好后邮件应用更改
刚才我们没有改变原字符串的长度,只修改了内容,那么如果想要扩容或缩减字符串长度又该怎么办呢?
如果我们改变了字符串的长度,那么会带来如下问题:
- 空间不足:原字符串所在节区(section)没有足够空间容纳更长内容
- 地址引用失效:程序中引用该字符串的指令(如
lea rdi, [str])可能需要调整
详细操作如下:
修改代码¶
#include <stdio.h>
#include <string.h>
int main() {
const char* passkey = "password@123";
char userinput[20];
printf("Input password: ");
scanf("%19s", userinput);
if (strcmp(userinput, passkey) == 0) {
printf("Check successfully!\n");
}
else {
printf("Wrong passkey!\n");
}
return 0;
}
以上是一个简单验证passkey的程序,将用户输入与硬编码的passkey比对,一致则打印验证成功,如果我们想要通过修改汇编代码来绕过其检查逻辑,应该如何做呢?

同样先找到主程序,随后将反汇编代码转换为伪C代码
int __fastcall main(int argc, const char **argv, const char **envp)
{
char userinput[24]; // [rsp+10h] [rbp-20h] BYREF
unsigned __int64 v5; // [rsp+28h] [rbp-8h]
v5 = __readfsqword(0x28u);
printf("Input password: ");
__isoc99_scanf("%19s", userinput);
if ( !strcmp(userinput, "password@123") )
puts("Check successfully!");
else
puts("Wrong passkey!");
return 0;
}

显然绕过的关键在于If语句判断,右键与汇编代码页面同步,随后切换到汇编代码页面

关键汇编代码如下:
mov rdx, [rbp+passkey]
lea rax, [rbp+userinput]
mov rsi, rdx ; s2
mov rdi, rax ; s1
call _strcmp
test eax, eax
jnz short loc_401221
从第四句开始是在变量比较,jnz short loc_401221根据返回值进行分支判断,其中loc_401221通过流程图可以看到是当passkey错误时会执行的分支,jnz表示当返回值不等与0时,会跳转到之后的分支,基于此,我们有以下修改方式:
- 正确/错误逻辑反转,输入错误passkey反而能检测成功
只需要将jnz修改为jz即可

找到**Assemble**,将jnz修改为jz

可以看到已经修改成功,并且流程图也随之变化,接下来就是保存patch到程序


保存成功后运行,修改成功
- 任意passkey都通过
有两种简单方法可以实现
第一种方法:
将jz short loc_401221修改为nop nop即可,nop是一个补位字节,字节是0x90,因为原语句占两个字节(0x74 0x0c),所以需要两个nop替换

选择字节修改,将74 0c改为90 90

这样程序不管passkey是否正确,都会检测通过
第二种方法:
将jnz修改为jmp(无条件跳转),并将跳转地址改为正确分支的地址
首先获取正确分支的地址:

为0000000000401215,随后直接修改指令
执行隐藏函数¶
#include <stdio.h>
void hidden_function() {
printf("This is a hidden function.\n");
}
void visible_function() {
printf("This is a visible function.\n");
}
int main() {
visible_function();
printf("Can you find the hidden function?");
return 0;
}
编译
我们的目的在于改变原有程序的逻辑,使其执行原程序不会执行的hidden_function函数,以下为分析过程
寻找主程序¶
在C语言中,默认的主程序由main函数开始,所以我们可以首先在函数列表中搜索main关键字

这里我们运气好,程序使用默认的main函数作为入口,双击,进入mian函数逻辑
; Attributes: bp-based frame
; int __fastcall main(int argc, const char **argv, const char **envp)
public main
main proc near
; __unwind {
endbr64
push rbp
mov rbp, rsp
mov eax, 0
call visible_function
mov edi, offset format ; "Can you find the hidden function?"
mov eax, 0
call _printf
mov eax, 0
pop rbp
retn
; } // starts at 401180
main endp
_text ends
那么可以看到main中call了visible_function函数,那么如果我们找到hidden_function函数地址,并替换visible_function函数的地址,那么main中就会call hidden_function函数,进而执行隐藏函数
找到hidden_function函数地址¶
我们同样在函数列表中搜索hidden_function,双击

可以在下方看到地址为0x401156,因为为32位程序,补全32-6*4=8位,完整地址为0x00401156
替换函数地址¶
X64dbg/X32dbg使用¶
修改数据¶
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Hello, Windows!\n");
system("pause");
return 0;
}
编译
gcc -m32 hello.c -o hello.exe -Wl,--disable-dynamicbase -Wl,--disable-nxcompat
# 禁用 DEP(数据执行保护),禁用 ASLR(地址空间布局随机化)
使用x32dbg打开

有两种打开方式,第一种是打开文件,第二种是附加到进程,一般而言第二种效果会更好一点,能帮助我们绕过一些检测,但由于我们这个程序很简单,所以直接打开即可
寻找主程序¶

点击符号,找到我们的exe文件,双击进入主模块

我们知道程序会打印Hello Windows!,那么我们可以搜索该字符串定位到相关代码地址,右键搜索字符串(Shfit+D)


找到目标字符串后双击进入

修改字符串的16进制¶
然后我们需要找到字符串的16进制值的地址,右键转到对应地址


勾选后右键二进制编辑


将原字符串改为Hello, Hackers!,保存,随后继续运行程序

此时已打印出我们修改后的字符串
修改代码¶
#include <stdio.h>
#include <string.h>
int main() {
const char* passkey = "password@123";
char userinput[20];
printf("Input password: ");
scanf("%19s", userinput);
if (strcmp(userinput, passkey) == 0) {
printf("Check successfully!\n");
}
else {
printf("Wrong passkey!\n");
}
return 0;
}

同样先找到主程序,我们右键查看流程图(G)


显然关键的判断语句在jne hello.401040,修改方案如下:
- 正确/错误逻辑反转,输入错误passkey反而能检测成功
只需要将jnz改为jz即可

在对应语句右键汇编(Space),修改jnz为jz

随后继续执行程序,输入错误的passkey