x64dbg脚本 - 解决调试时自定义调用函数方式
一直没怎么使用x64dbg脚本功能,而且官方的文档命令的例子也不多,所以整理了下,解决的问题来原于这次Q3的CTF第5题,在做3DES的时候,程序逻辑为:
Dest= UserInput[18, 8]
v21 = UserInput[16, 8]; = "VXV9/DCo"
v22 = UserInput[8, 8]; = "VXV8/wCp"
v23 = UserInput[0, 8]; = "VXX/8AKl"
des_Func_en(&Dest, &v21, &Dest); // crypt
des_Func_de(&Dest, &v22, &Dest); // decrypt
des_Func_en(&Dest, &v23, &Dest); // crypt
// 执行后此处Dest = ['0x30', '0x80', '0x3', '0x3f', '0xfd', '0x55', '0x5a', '0x80']
上面的CTF相关的内容就略了,其中需要逆向得到Dest的值,需要对上面的三次调用逆过程执行,基本为:
Dest = ['0x30', '0x80', '0x3', '0x3f', '0xfd', '0x55', '0x5a', '0x80']
v21 = UserInput[16, 8]; = "VXV9/DCo"
v22 = UserInput[8, 8]; = "VXV8/wCp"
v23 = UserInput[0, 8]; = "VXX/8AKl"
des_Func_de(&Dest, &v23, &Dest); // decrypt
des_Func_en(&Dest, &v22, &Dest); // crypt
des_Func_de(&Dest, &v21, &Dest); // decrypt
如果手工调试,可以在断点到对应函数后,通过修改参数来实现,但是因为顺序问题,需要3次完成调试,其中在使用脚本语言相关的调试的时候,是可以在调试阶段,动态去调用一些函数,来测试结果的,所以想着是不是有办法做到类似的功能(本来想看是不是有插件可以,没有找到),就开始找办法实现。
实现思路
在二进制里要实现上面的调用,想到的一个思路是通过动态写汇编来执行:
1,先创建一块调试临时内存区域用来存放需要写的汇编;
2,将上面的逆过程以汇编的方式写到内存区域;
3,在调试的时候,执行到合适的断点后,进入上面的汇编获取结果;
根据上面的方式,分别要解决几个问题:
1,内存分配:alloc
2,des_Func_de|des_Func_en的调用参数和地址:通过查看原来的内容获取:
// des_Func_en :
lea rcx,qword ptr ss:[rbp-10]
lea rdx,qword ptr ss:[rbp-40]
lea rax,qword ptr ss:[rbp-10]
mov r8,rcx
mov rcx,rax
call <lost.sub_4023E4_DES_Func_en> | call 4023E4(rcx, rdx, r8)
// des_Func_den :
lea rcx,qword ptr ss:[rbp-10]
lea rdx,qword ptr ss:[rbp-30]
lea rax,qword ptr ss:[rbp-10]
mov r8,rcx
mov rcx,rax
call <lost.sub_40202A_DES_Func_de> | call 40202A(rcx, rdx, r8)
des_Func_de :
3, 写入汇编还是shellcode ?通过查看手册,其实x64dbg的汇编器是可以调用的:asm 命令;
接下来就是coding和debug的过程,不细说了,有一些命令不熟悉,自己也摸索了下;
脚本结果:
// This is a demo of x64dbg
// In x64dbg script, use cmp and je to work like "if and for " in high class language.
// Note: 22fd30, 22fd20, 22fd10, 22fd00 are fixed addresses in debug.
// ------------------------------------------------------------------------------------
// set dest = ['0x30', '0x80', '0x3', '0x3f', '0xfd', '0x55', '0x5a', '0x80']
Fill 22FD30,30,1;Fill 22FD30+1,80,1;Fill 22FD30+2,03,1;
Fill 22FD30+3,3F,1;Fill 22FD30+4,FD,1;Fill 22FD30+5,55,1;
Fill 22FD30+6,5A,1;Fill 22FD30+7,80,1;
// allocate memory , note: set @address may get faliure.
alloc 0x1000
// write code to memory
$inst_base=$result + 0x10
$inst_offset=0
asm $inst_base, "mov edx, 0x22FD20"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "lea rcx, ss:[rbp-0x10]"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "lea rax, ss:[rbp-0x10]"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "mov r8, rcx"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "mov rcx, rax"
$inst_offset = $inst_offset + $result
log "inst_offset = {0}, result = {1}", $inst_offset, $result
// call 0x40202A(rcx, rdx, r8)
asm $inst_base + $inst_offset, "call 0x40202A"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "lea rcx, ss:[rbp-0x10]"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "lea rax, ss:[rbp-0x10]"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "mov r8, rcx"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "mov rcx, rax"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "mov edx, 0x22FD10"
$inst_offset = $inst_offset + $result
// call 0x4023E4(rcx, rdx, r8)
asm $inst_base + $inst_offset, "call 0x4023E4"
log "inst_offset = {0}, result = {1}", $inst_offset, $result
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "lea rcx, ss:[rbp-0x10]"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "lea rax, ss:[rbp-0x10]"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "mov r8, rcx"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "mov rcx, rax"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "mov edx, 0x22FD00"
$inst_offset = $inst_offset + $result
// call 0x40202A(rcx, rdx, r8)
asm $inst_base + $inst_offset, "call 0x40202A"
$inst_offset = $inst_offset + $result
asm $inst_base + $inst_offset, "nop"
bp $inst_base + $inst_offset
log "inst_offset = {0}, result = {1}", $inst_offset, $result
// set run point
rip = $inst_base
run
log "Result = 0x" "{x:bswap([0x22FD30])}" // show 8 bytes info of address 22fd30.
log "Result = 0x" "{mem;8@0x22FD30}" // Demo how to set size of showed bytes.
说明:最后Demo了一下按字节显示的格式,官方文档没提命令需要加“”,而且有一些格式不加“”也可以,有点乱。
测试结果
完成上面的脚本后,加载lost.exe程序,手动设置断点:
程序正常输入:VXX/8AKlVXV8/wCpVXV9/DCo
停在断点后,加载脚本,并执行,在日志界面查看结果:
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界
最后于 2019-9-27 17:42
被nevinhappy编辑
,原因: