常见压缩壳脱壳分析

1.UPX壳

文件下载ELF

先分析一下文件,发现有UPX壳。elf

![屏幕截图 2025-10-09 161748](C:\Users\xiler\Pictures\Screenshots\屏幕截图 2025-10-09 161748.png

放入010中也没有发现很明显的UPX特性,尝试手动脱壳

img

这里有一个小插曲是程序类型可能是DYN,

ida动调时会提示:”Inputfile is a dynamic file…”无法调试

这时候可以修改文件头信息从03->DYN改为02->EXEC

img

这里附一张gemini的解释:其原理是骗过ida的检测

常见压缩壳脱壳分析/image-20251009164715550

kali中启动远程调试

img

ida中在start处下断点,进行调试

img

进来后一直F8b步过可以看到这个地方,继续往下步过

img

继续步过到这里,然后步进

img

进来后是这个,这里有三个循环,直接跳过,可以下断点跳过去,这里步过的一大串,还调用syscall,这些都是在调用解密函数来自解密这个压缩壳

img

常见压缩壳脱壳分析/image-20251009163305368

一直步过到这里,这里的jmp qword ptr [r14-8]算是喝oep类似的一个特征在这里需要步进不能步过,否则进去会卡住

常见压缩壳脱壳分析/image-20251009163434507

常见压缩壳脱壳分析/image-20251009163644997

到这里,步过到r12后步进,就可以看到oep了,在这里可以选择直接dump数据,静态分析做,也可以选择动态调试直接做

img

可以进去按一下p构建函数,就可以看到主函数了

常见压缩壳脱壳分析/image-20251009164831947

也可以直接选择dump数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# -*- coding: utf-8 -*-

from ida_bytes import get_bytes
from ida_kernwin import ask_addr, ask_file, warning, info
import ida_segment

def dump_memory_to_file():
"""
从IDA数据库中dump指定范围的内存到文件中。
"""
# 1. 获取要dump的内存范围
# 尝试获取当前光标所在的段作为默认范围
current_ea = get_screen_ea()
current_seg = ida_segment.getseg(current_ea)

default_start = current_seg.start_ea if current_seg else 0
default_end = current_seg.end_ea if current_seg else 0x10000

start_addr = ask_addr(default_start, "请输入起始地址 (start address):")
if start_addr is None:
info("操作已取消。")
return

end_addr = ask_addr(default_end, "请输入结束地址 (end address):")
if end_addr is None:
info("操作已取消。")
return

# 2. 地址合法性校验
if start_addr >= end_addr:
warning(f"起始地址 ${start_addr:x}$ 不能大于或等于结束地址 ${end_addr:x}$。")
return

size = end_addr - start_addr
print(f"准备从 ${start_addr:x}$ dump 到 ${end_addr:x}$ (大小: {size} 字节)...")

# 3. 获取内存内容
try:
content = get_bytes(start_addr, size)
if not content:
warning(f"无法从地址范围 ${start_addr:x}$ - ${end_addr:x}$ 读取到有效数据。")
return
except Exception as e:
warning(f"使用 get_bytes 时发生错误: {e}")
return

# 4. 获取保存路径
# 建议默认文件名,并允许用户修改
default_filename = f"dump_{start_addr:x}_{end_addr:x}.bin"
save_path = ask_file(1, default_filename, "请选择保存路径和文件名")

if not save_path:
info("操作已取消。")
return

# 5. 写入文件 (使用 with 语句)
try:
with open(save_path, "wb") as f:
f.write(content)
info(f"成功将 {len(content)} 字节的数据写入到:\n{save_path}")
except IOError as e:
warning(f"写入文件时发生错误: {e}")

# --- 执行脚本 ---
if __name__ == "__main__":
dump_memory_to_file()

dump的范围是0到第二个load的end地址

img

以下是gemini的解释

img

可以看到成功脱壳了

常见压缩壳脱壳分析/image-20251009164240213