Skip to content

Commit

Permalink
使用 Unicorn 如何进行栈读写 和 Patch
Browse files Browse the repository at this point in the history
  • Loading branch information
CYRUS-STUDIO committed Feb 23, 2025
1 parent e81c44a commit 1d72f56
Show file tree
Hide file tree
Showing 17 changed files with 1,073 additions and 174 deletions.
249 changes: 249 additions & 0 deletions content/posts/使用 Unicorn 如何进行栈读写 和 Patch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
+++
title = '使用 Unicorn 如何进行栈读写 和 Patch'
date = 2025-02-23T17:56:08.538560+08:00
draft = false
+++

> 版权归作者所有,如有转发,请注明文章出处:<https://cyrus-studio.github.io/blog/>
# **struct.pack 方法介绍**



struct.pack 是 Python 标准库 struct 模块中的一个函数,它用于将 Python 的基本数据类型(如 int、float、long)打包为字节流,以便在二进制文件、网络传输或内存操作(如 Unicorn 仿真器的 mem_write)中使用。



语法:

```
import struct
struct.pack(format, value)
```
- format:指定数据的格式,例如:

- <f:表示小端(<)的 4 字节浮点数(float)

- <d:表示小端的 8 字节双精度浮点数(double)

- value:要转换的 Python 值。



**数据类型格式**

| 数据类型 | 有符号格式(小写) | 无符号格式(大写) | 大小(字节) |
|--- | --- | --- | ---|
| byte | b (char) | B (uchar) | 1 |
| short | h (short) | H (ushort) | 2 |
| int | i (int) | I (uint) | 4 |
| long | q (long long) | Q (ulong long) | 8 |
| float | f (float) || 4 |
| double | d (double) || 8 |


**其他特殊类型**

| 格式 | 说明 | 字节数 |
|--- | --- | ---|
| x | 跳过的填充字节 | 1 |
| s | char[](字符串) | 可变 |
| p | Pascal 风格字符串(首字节存长度) | 可变 |
| ? | bool(布尔值) | 1 |


**字节顺序(大小端)**

| 前缀 | 说明 |
|--- | ---|
| @ | 按本机字节顺序存储 |
| < | 小端(Little-Endian) |
| > | 大端(Big-Endian) |
| = | 按本机字节序存储(无对齐) |
| ! | 网络字节序(大端,等价于 > ) |


# **Unicorn 中栈读写示例**



使用 Unicorn 模拟器进行栈操作,并使用 struct 处理数据打包/解包。

```
from unicorn import Uc, UC_ARCH_ARM64, UC_MODE_ARM
from unicorn.arm64_const import *
import struct
# 定义内存布局
STACK_ADDR = 0x400000 # 栈基址
STACK_SIZE = 0x10000 # 栈大小
# 初始化 Unicorn
mu = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
# 分配栈空间
mu.mem_map(STACK_ADDR, STACK_SIZE)
# 设置 SP(栈指针)
sp_init = STACK_ADDR + STACK_SIZE - 0x10 # 预留一点空间
mu.reg_write(UC_ARM64_REG_SP, sp_init)
# 直接写入各种数据类型到栈
sp = mu.reg_read(UC_ARM64_REG_SP)
# 写入 byte
byte_value = 0x12
sp -= 1
mu.mem_write(sp, struct.pack('<B', byte_value))
print(f"Pushed byte {hex(byte_value)} to stack at {hex(sp)}")
# 写入 short
short_value = 0x1234
sp -= 2
mu.mem_write(sp, struct.pack('<H', short_value))
print(f"Pushed short {hex(short_value)} to stack at {hex(sp)}")
# 写入 int
int_value = 0x12345678
sp -= 4
mu.mem_write(sp, struct.pack('<I', int_value))
print(f"Pushed int {hex(int_value)} to stack at {hex(sp)}")
# 写入 long
long_value = 0x12345678ABCDEF01
sp -= 8
mu.mem_write(sp, struct.pack('<Q', long_value))
print(f"Pushed long {hex(long_value)} to stack at {hex(sp)}")
# 写入 float
float_value = 3.14
sp -= 4
mu.mem_write(sp, struct.pack('<f', float_value))
print(f"Pushed float {float_value} to stack at {hex(sp)}")
# 写入 double
double_value = 2.718281828459
sp -= 8
mu.mem_write(sp, struct.pack('<d', double_value))
print(f"Pushed double {double_value} to stack at {hex(sp)}")
mu.reg_write(UC_ARM64_REG_SP, sp)
# 直接从栈读取数据
# 读取 double
double_read = struct.unpack('<d', mu.mem_read(sp, 8))[0]
print(f"Popped double {double_read} from stack at {hex(sp)}")
sp += 8
# 读取 float
float_read = struct.unpack('<f', mu.mem_read(sp, 4))[0]
print(f"Popped float {float_read} from stack at {hex(sp)}")
sp += 4
# 读取 long
long_read = struct.unpack('<Q', mu.mem_read(sp, 8))[0]
print(f"Popped long {hex(long_read)} from stack at {hex(sp)}")
sp += 8
# 读取 int
int_read = struct.unpack('<I', mu.mem_read(sp, 4))[0]
print(f"Popped int {hex(int_read)} from stack at {hex(sp)}")
sp += 4
# 读取 short
short_read = struct.unpack('<H', mu.mem_read(sp, 2))[0]
print(f"Popped short {hex(short_read)} from stack at {hex(sp)}")
sp += 2
# 读取 byte
byte_read = struct.unpack('<B', mu.mem_read(sp, 1))[0]
print(f"Popped byte {hex(byte_read)} from stack at {hex(sp)}")
sp += 1
mu.reg_write(UC_ARM64_REG_SP, sp)
print("Stack read/write successful for all data types!")
```


输出如下:

```
Pushed byte 0x12 to stack at 0x40ffef
Pushed short 0x1234 to stack at 0x40ffed
Pushed int 0x12345678 to stack at 0x40ffe9
Pushed long 0x12345678abcdef01 to stack at 0x40ffe1
Pushed float 3.14 to stack at 0x40ffdd
Pushed double 2.718281828459 to stack at 0x40ffd5
Popped double 2.718281828459 from stack at 0x40ffd5
Popped float 3.140000104904175 from stack at 0x40ffdd
Popped long 0x12345678abcdef01 from stack at 0x40ffe1
Popped int 0x12345678 from stack at 0x40ffe9
Popped short 0x1234 from stack at 0x40ffed
Popped byte 0x12 from stack at 0x40ffef
Stack read/write successful for all data types!
```


# **Unicorn 中 Patch 示例**



在 Unicorn 中,可以通过 mem_write 方法直接修改指定地址的指令数据。例如,要将某个位置的指令替换为 NOP。



在 ARM64 架构下,NOP 指令的机器码是:

```
NOP = 0xD503201F # (ARM64 指令,大端)
```
它占用 4 字节。



假设你要将 0x1000 处的指令替换为 NOP:

```
import struct
from unicorn import Uc, UC_ARCH_ARM64, UC_MODE_ARM
# 初始化 Unicorn
mu = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
# 分配内存(假设代码段在 0x1000 处)
CODE_ADDR = 0x1000
CODE_SIZE = 0x1000
mu.mem_map(CODE_ADDR, CODE_SIZE)
# 写入示例代码(假设已有一些指令)
original_code = b"\x00\x00\xA0\xE3" # 伪造一条指令(MOV R0, #0)
mu.mem_write(CODE_ADDR, original_code)
# 替换为 NOP 指令
nop_opcode = struct.pack("<I", 0xD503201F) # ARM64 NOP 指令(小端存储)
mu.mem_write(CODE_ADDR, nop_opcode)
# 读取并验证
patched_code = mu.mem_read(CODE_ADDR, 4)
print(f"Patched instruction: {patched_code.hex()}") # 应输出 "1f2003d5"
```


输出如下:

```
Patched instruction: 1f2003d5
```
从输出可以看到已经成功将指定地址的指令 Patch 为 NOP 了。











34 changes: 17 additions & 17 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@
<h1>CYRUS STUDIO</h1>
<ul class="posts-list">

<li class="posts-list-item">
<a class="posts-list-item-title" href="https://cyrus-studio.github.io/blog/posts/%E4%BD%BF%E7%94%A8-unicorn-%E5%A6%82%E4%BD%95%E8%BF%9B%E8%A1%8C%E6%A0%88%E8%AF%BB%E5%86%99-%E5%92%8C-patch/">使用 Unicorn 如何进行栈读写 和 Patch</a>
<span class="posts-list-item-description">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-calendar">
<title>calendar</title>
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line>
</svg>
Feb 23, 2025
<span class="posts-list-item-separator">-</span>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-clock">
<title>clock</title>
<circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline>
</svg>
3 min read
</span>
</li>

<li class="posts-list-item">
<a class="posts-list-item-title" href="https://cyrus-studio.github.io/blog/posts/unicorn-hook-%E8%AF%A6%E8%A7%A3%E6%8C%87%E4%BB%A4%E4%BB%A3%E7%A0%81%E5%9D%97%E5%86%85%E5%AD%98%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E7%AD%89/">Unicorn Hook 详解:指令、代码块、内存、系统调用等</a>
<span class="posts-list-item-description">
Expand Down Expand Up @@ -214,23 +231,6 @@ <h1>CYRUS STUDIO</h1>
</span>
</li>

<li class="posts-list-item">
<a class="posts-list-item-title" href="https://cyrus-studio.github.io/blog/posts/%E7%A7%BB%E6%A4%8D-ollvm-%E5%88%B0-llvm18%E4%BF%AE%E5%A4%8D%E6%8E%A7%E5%88%B6%E6%B5%81%E5%B9%B3%E5%9D%A6%E5%8C%96%E6%8A%A5%E9%94%99/">移植 OLLVM 到 LLVM18,修复控制流平坦化报错</a>
<span class="posts-list-item-description">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-calendar">
<title>calendar</title>
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line>
</svg>
Dec 21, 2024
<span class="posts-list-item-separator">-</span>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-clock">
<title>clock</title>
<circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline>
</svg>
3 min read
</span>
</li>

</ul>


Expand Down
9 changes: 8 additions & 1 deletion public/index.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@
<description>Recent content on CYRUS STUDIO</description>
<generator>Hugo</generator>
<language>zh-cn</language>
<lastBuildDate>Mon, 10 Feb 2025 00:06:11 +0800</lastBuildDate>
<lastBuildDate>Sun, 23 Feb 2025 17:56:08 +0800</lastBuildDate>
<atom:link href="https://cyrus-studio.github.io/blog/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>使用 Unicorn 如何进行栈读写 和 Patch</title>
<link>https://cyrus-studio.github.io/blog/posts/%E4%BD%BF%E7%94%A8-unicorn-%E5%A6%82%E4%BD%95%E8%BF%9B%E8%A1%8C%E6%A0%88%E8%AF%BB%E5%86%99-%E5%92%8C-patch/</link>
<pubDate>Sun, 23 Feb 2025 17:56:08 +0800</pubDate>
<guid>https://cyrus-studio.github.io/blog/posts/%E4%BD%BF%E7%94%A8-unicorn-%E5%A6%82%E4%BD%95%E8%BF%9B%E8%A1%8C%E6%A0%88%E8%AF%BB%E5%86%99-%E5%92%8C-patch/</guid>
<description>版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/&#xA;struct.pack 方法介绍 struct.pack 是 Python 标准库 struct 模块中的一个函数,它用于将 Python 的基本数据类型(如 int、float、long)打包为字节流,以便在二进制文件、网络传输或内存操作(如 Unicorn 仿真器的 mem_write)中使用。&#xA;语法:&#xA;import struct&#xD;struct.pack(format, value) format:指定数据的格式,例如:&#xA;&amp;lt;f:表示小端(&amp;lt;)的 4 字节浮点数(float)&#xA;&amp;lt;d:表示小端的 8 字节双精度浮点数(double)&#xA;value:要转换的 Python 值。&#xA;数据类型格式&#xA;数据类型 有符号格式(小写) 无符号格式(大写) 大小(字节) byte b (char) B (uchar) 1 short h (short) H (ushort) 2 int i (int) I (uint) 4 long q (long long) Q (ulong long) 8 float f (float) 无 4 double d (double) 无 8 其他特殊类型</description>
</item>
<item>
<title>Unicorn Hook 详解:指令、代码块、内存、系统调用等</title>
<link>https://cyrus-studio.github.io/blog/posts/unicorn-hook-%E8%AF%A6%E8%A7%A3%E6%8C%87%E4%BB%A4%E4%BB%A3%E7%A0%81%E5%9D%97%E5%86%85%E5%AD%98%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E7%AD%89/</link>
Expand Down
34 changes: 17 additions & 17 deletions public/page/2/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@
<h1>CYRUS STUDIO</h1>
<ul class="posts-list">

<li class="posts-list-item">
<a class="posts-list-item-title" href="https://cyrus-studio.github.io/blog/posts/%E7%A7%BB%E6%A4%8D-ollvm-%E5%88%B0-llvm18%E4%BF%AE%E5%A4%8D%E6%8E%A7%E5%88%B6%E6%B5%81%E5%B9%B3%E5%9D%A6%E5%8C%96%E6%8A%A5%E9%94%99/">移植 OLLVM 到 LLVM18,修复控制流平坦化报错</a>
<span class="posts-list-item-description">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-calendar">
<title>calendar</title>
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line>
</svg>
Dec 21, 2024
<span class="posts-list-item-separator">-</span>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-clock">
<title>clock</title>
<circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline>
</svg>
3 min read
</span>
</li>

<li class="posts-list-item">
<a class="posts-list-item-title" href="https://cyrus-studio.github.io/blog/posts/%E7%BC%96%E8%AF%91-llvm-%E6%BA%90%E7%A0%81%E4%BD%BF%E7%94%A8-clion-%E8%B0%83%E8%AF%95-clang/">编译 LLVM 源码,使用 Clion 调试 clang</a>
<span class="posts-list-item-description">
Expand Down Expand Up @@ -214,23 +231,6 @@ <h1>CYRUS STUDIO</h1>
</span>
</li>

<li class="posts-list-item">
<a class="posts-list-item-title" href="https://cyrus-studio.github.io/blog/posts/%E8%AF%A6%E8%A7%A3arm64%E5%8F%AF%E6%89%A7%E8%A1%8C%E7%A8%8B%E5%BA%8F%E7%9A%84%E7%94%9F%E6%88%90%E8%BF%87%E7%A8%8B/">详解ARM64可执行程序的生成过程</a>
<span class="posts-list-item-description">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-calendar">
<title>calendar</title>
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line>
</svg>
Nov 2, 2024
<span class="posts-list-item-separator">-</span>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-clock">
<title>clock</title>
<circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline>
</svg>
6 min read
</span>
</li>

</ul>


Expand Down
Loading

0 comments on commit 1d72f56

Please sign in to comment.