台州市赛 - Reverse 方向
carbofish

台州市赛 Reverse 方向

nanomites

主函数
image.png

查看函数 sub_40195C
这里使用了Windows API中的CreateProcessAWaitForDebugEvent等函数。创建了一个新的进程并进入调试模式,通过处理调试事件(如创建线程、异常、退出等)来控制进程的执行

image.png

这里利用 dwDebugEventCode 来执行程序逻辑
常见的 dwDebugEventCode 事件类型及其对应的常量值如下:

  1. EXCEPTION_DEBUG_EVENT (值:1):
    • 表示一个异常发生了。调试器可以捕获各种类型的异常,包括访问冲突、除零、断点异常等。异常信息保存在 DEBUG_EVENT.u.Exception 中。
  2. CREATE_THREAD_DEBUG_EVENT (值:2):
    • 表示被调试的进程创建了一个新的线程。调试器可以通过该事件获取新线程的句柄。线程信息保存在 DEBUG_EVENT.u.CreateThread 中。
  3. CREATE_PROCESS_DEBUG_EVENT (值:3):
    • 表示被调试的进程启动。此事件发生在调试器启动的进程开始运行时。进程信息(如句柄)保存在 DEBUG_EVENT.u.CreateProcessInfo 中。
  4. EXIT_THREAD_DEBUG_EVENT (值:4):
    • 表示一个线程已经退出。调试器可以使用这个事件来清理和跟踪已退出的线程。退出信息保存在 DEBUG_EVENT.u.ExitThread 中。
  5. EXIT_PROCESS_DEBUG_EVENT (值:5):
    • 表示被调试的进程已经退出。调试器可以使用这个事件来获取进程的退出码并进行清理工作。退出信息保存在 DEBUG_EVENT.u.ExitProcess 中。
  6. LOAD_DLL_DEBUG_EVENT (值:6):
    • 表示被调试的进程加载了一个新的动态链接库(DLL)。调试器可以使用这个事件来获取DLL的句柄和路径。DLL信息保存在 DEBUG_EVENT.u.LoadDll 中。

核心加密逻辑是 case1 那个 EXCEPTION_DEBUG_EVENT 后面会讲到,我们一步一步看
我们看另外一个函数 sub_401C38

image.png

这里有一个运行时载入代码,我们把 unk_412020 导出然后 使用 ida 分析

image.png

可以看到主要逻辑是把传入的输入的数据加载一个字节到 r12 寄存器,然后对 r11 寄存器进行复制异或和循环位移,然后关键是 ud2 指令,这个是抛出异常,再联想到上面 EXCEPTION_DEBUG_EVENT
就可以知道加密逻辑了

image.png

sub_401584是加密函数,密文在 r11 寄存器中,然后只比较 r13 寄存器为 1 的情况,上面那么多 r13 为 0 的情况是假的
把上面 dump 出来的热加载的 shellcode disasm 然后用 python 提取出含有 mov r13, 1 的片段,然后我们就得计算出每个片段对应的 r11 值,也就是密文,这里考虑到精度,使用 unicorn 计算比较好

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
from unicorn import *
from unicorn.x86_const import *
import re

mu = Uc(UC_ARCH_X86, UC_MODE_64)

ADDRESS = 0x1000
mu.mem_map(ADDRESS, 2 * 1024 * 1024)

f = open("asm.txt", "r").read()

def executer(imm1, imm2, imm3):
mov_r11 = b'\x49\xbb' + imm1.to_bytes(8, byteorder='little')
xor_r11 = b'\x49\x81\xf3' + imm2.to_bytes(4, byteorder='little')
ror_r11 = b'\x49\xc1\xcb' + imm3.to_bytes(1, byteorder='little')
CODE = mov_r11 + xor_r11 + ror_r11
mu.mem_write(ADDRESS, CODE)
mu.reg_write(UC_X86_REG_R11, 0) # 初始化 R11 寄存器
mu.emu_start(ADDRESS, ADDRESS + len(CODE))
r11_value = mu.reg_read(UC_X86_REG_R11)
return r11_value

result = []

sp = f.split("; ---------------------------------------------------------------------------\n")
for part in sp:
pt = [_.strip() for _ in part.split("\n")[:-1]]
symbol = pt[4]
if symbol == "mov r13, 1":
num1 = int("0x" + re.findall(r"[\dA-Z]+h", pt[1])[0][:-1], 16)
num2 = int("0x" + re.findall(r"[\dA-Z]+h", pt[2])[0][:-1], 16)
num3 = int("0x" + re.findall(r"[\dA-Z]+h", pt[3])[0][:-1], 16)
result.append(executer(num1, num2, num3))
# print(f"{num1:#x}, {num2:#x}, {num3:#x}, {result[-1]: #x}")

for enc in result:
print(f"{enc:#x}, ", end="")

得到密文表

1
[0x84db9614, 0x174760d3, 0x7ac80e2c, 0x3194ec2e, 0x70a549c3, 0x41dedf66, 0x7f69c81e, 0x37b76e13, 0x37b76e13, 0x41dedf66, 0xb99d68d8, 0xcfef5b0b, 0x174760d3, 0xb78ac2e7, 0xea1b9f56, 0xee54ef8e, 0x174760d3, 0xb99d68d8, 0xf2475372, 0xdc310a37, 0xee54ef8e, 0x37b76e13, 0x3194ec2e, 0x37b76e13, 0xea1b9f56, 0xee54ef8e, 0xb99d68d8, 0xea1b9f56, 0xb78ac2e7, 0x9d07d8da, 0xee54ef8e, 0x41dedf66, 0x8288d321, 0x174760d3, 0x9d07d8da, 0x174760d3, 0x8288d321, 0xdc310a37, 0x45e26648, 0x41dedf66, 0x8288d321, 0x8288d321, 0x930b26e3, 0xabef6fef]

观察异常处理中的加密函数

image.png

是一系列较为复杂的位移操作,应该是可以解的,但是笔者采取了一个投巧的方法,用x64dbg下断在 0x0000000000401862

image.png

由于可视字符太多,所以笔者写了一个脚本来自动打印到日志

1
2
3
run                               
log SYM:"{mem;1@61F726}": "{rax}"
ret

然后在flag输入处输入全可打印字符

1
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~

提取出对应表

1
{2596959767: '!', 3278025627: '"', 1199340385: '#', 3652842418: '$', 3416942461: '%', 723666731: '&', 280982008: "'", 3348210159: '(', 1029965590: ')', 1646217348: '*', 1509106344: '+', 1884266855: ',', 3998543758: '-', 10365811: '.', 3246951466: '/', 4064760690: '0', 3927678806: '1', 2190005025: '2', 2634537178: '3', 3418004561: '4', 3079324391: '5', 3488570123: '6', 1172465224: '7', 2466981603: '8', 3694201399: '9', 1612783687: ':', 693140910: ';', 3726077530: '<', 1307370518: '=', 726644641: '>', 1786144152: '?', 2537538325: '@', 390553811: 'A', 934768147: 'B', 831843374: 'C', 2228983316: 'D', 3114100952: 'E', 1105125222: 'F', 2398680771: 'G', 3353174339: 'H', 3250317036: 'I', 870428025: 'J', 3051147020: 'K', 120575263: 'L', 1208782285: 'M', 2708701790: 'N', 84861922: 'O', 2027386979: 'P', 1073431481: 'Q', 867118355: 'R', 2059931180: 'S', 1889880515: 'T', 4144402592: 'U', 157475374: 'V', 3597550946: 'W', 3904163235: 'X', 3052880830: 'Y', 1826329493: 'Z', 3635011357: '[', 2712232590: '\\', 2987677768: ']', 2851724154: '^', 2131826772: '_', 2472816263: '`', 291415938: 'a', 1891737825: 'b', 4106698431: 'c', 51373921: 'd', 3596199336: 'e', 86081972: 'f', 429896102: 'g', 1213478405: 'h', 1178941954: 'i', 2136545382: 'j', 1319470528: 'k', 2682404089: 'l', 2376513170: 'm', 3465855092: 'n', 1867828354: 'o', 2685652659: 'p', 1457933662: 'q', 3227490855: 'r', 3060405360: 's', 1697040329: 't', 294797628: 'u', 2577271396: 'v', 1420360541: 'w', 260209567: 'x', 2851528244: 'y', 2240464916: 'z', 2137638942: '{', 808490953: '|', 2884595695: '}', 3702355519: '~'}

然后一一查询,就可以得到flag DASCTF{BBFE6A51-AE09-BCB1-E153-F2A3A297F228}

由 Hexo 驱动 & 主题 Keep
访客数 访问量