跳转至

逆向环境搭建

逆向工具

静态分析工具

IDA Pro

下载地址:IDA Pro: Powerful Disassembler, Decompiler & Debugger

支持Macos、Windows、Linux等平台,建议找个破解版下载

010editor

下载地址:010 Editor - Pro Text/Hex Editor | Edit 300+ Formats | Fast & Powerful | Reverse Engineering

文件16进制分析器,同样支持多平台

PE-bear

下载地址:Releases · hasherezade/pe-bear

支持多平台

Ghidra

下载地址:GitHub - NationalSecurityAgency/ghidra: Ghidra is a software reverse engineering (SRE) framework

开源工具,支持多平台

动态调试工具

X64dbg

下载地址:x64dbg

开源工具,仅支持Windows平台

Windbg

下载地址:Windbg调试工具 - 官方资源与指南

微软官方工具,仅支持Windows平台,专用于调试Windows内核程序

查壳工具

PEID

下载地址:PEiD - Download - Softpedia

仅支持Windows平台

DIE

下载地址:horsicq/Detect-It-Easy: Program for determining types of files for Windows, Linux and MacOS.

支持多平台

IDA Pro使用

我们直接用一些示例来演示

修改数据

C
#include <stdio.h>

int main() {
    printf("Hello World!\n");
    return 0;
}

这是一个简单的hello world程序,如果我们想要修改其打印的字符串,应该怎么办呢,首先我们使用IDA打开

image-20260103221455285

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

image-20260103221718603

双击字符串

image-20260103221749083

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

image-20260103221914644

打开16进制页面

image-20260103221945349

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

Bash
echo -n "Hello Admin!" | xxd
00000000: 4865 6c6c 6f20 4164 6d69 6e21            Hello Admin!

对应的16进制为4865 6c6c 6f20 4164 6d69 6e21

image-20260103223413507

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

image-20260103223453194

image-20260103223724407

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

image-20260103224111470

如果要使用ida修改16进制,右键edit,编辑好后邮件应用更改


刚才我们没有改变原字符串的长度,只修改了内容,那么如果想要扩容或缩减字符串长度又该怎么办呢?

如果我们改变了字符串的长度,那么会带来如下问题:

  1. 空间不足:原字符串所在节区(section)没有足够空间容纳更长内容
  2. 地址引用失效:程序中引用该字符串的指令(如 lea rdi, [str])可能需要调整

详细操作如下:

修改代码

C
#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比对,一致则打印验证成功,如果我们想要通过修改汇编代码来绕过其检查逻辑,应该如何做呢?

image-20260103232028879

同样先找到主程序,随后将反汇编代码转换为伪C代码

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;
}

image-20260104162236841

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

image-20260104162350044

关键汇编代码如下:

GAS
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时,会跳转到之后的分支,基于此,我们有以下修改方式:

  1. 正确/错误逻辑反转,输入错误passkey反而能检测成功

只需要将jnz修改为jz即可

image-20260104164756278

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

image-20260104165024299

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

image-20260104165146961

image-20260104170226996

保存成功后运行,修改成功

  1. 任意passkey都通过

有两种简单方法可以实现

第一种方法:

将jz short loc_401221修改为nop nop即可,nop是一个补位字节,字节是0x90,因为原语句占两个字节(0x74 0x0c),所以需要两个nop替换

image-20260104172041442

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

image-20260104172145517

这样程序不管passkey是否正确,都会检测通过


第二种方法:

将jnz修改为jmp(无条件跳转),并将跳转地址改为正确分支的地址

首先获取正确分支的地址:

image-20260104172842274

为0000000000401215,随后直接修改指令

执行隐藏函数

C
#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;
}

编译

Bash
gcc -O0 -g -fno-pie -no-pie -o test test.c
# -O0(无优化)、-g(保留调试符号)、-fno-pie(禁用地址随机化,便于静态分析)

我们的目的在于改变原有程序的逻辑,使其执行原程序不会执行的hidden_function函数,以下为分析过程

寻找主程序

在C语言中,默认的主程序由main函数开始,所以我们可以首先在函数列表中搜索main关键字

image-20251231215821377

这里我们运气好,程序使用默认的main函数作为入口,双击,进入mian函数逻辑

GAS
; 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,双击

image-20251231221041630

可以在下方看到地址为0x401156,因为为32位程序,补全32-6*4=8位,完整地址为0x00401156

替换函数地址

X64dbg/X32dbg使用

修改数据

C
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("Hello, Windows!\n");
    system("pause");
    return 0;
}

编译

Text Only
gcc -m32 hello.c -o hello.exe -Wl,--disable-dynamicbase -Wl,--disable-nxcompat
# 禁用 DEP(数据执行保护),禁用 ASLR(地址空间布局随机化)

使用x32dbg打开

image-20260105225652292

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

寻找主程序

image-20260105225851434

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

image-20260105230213705

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

image-20260105230325125

image-20260105230405965

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

image-20260105230439680

修改字符串的16进制

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

image-20260105230651014

image-20260105230724914

勾选后右键二进制编辑

image-20260105230754539

image-20260105230819237

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

image-20260105230937150

此时已打印出我们修改后的字符串

修改代码

C
#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;
}

image-20260105231942572

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

image-20260105232045362

image-20260105232108190

显然关键的判断语句在jne hello.401040,修改方案如下:

  1. 正确/错误逻辑反转,输入错误passkey反而能检测成功

只需要将jnz改为jz即可

image-20260105232533626

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

image-20260105232625413

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