羊城杯2023
CSGO
学习到了sharpOD orz
IDA的话没办法动调 至少很难动调
FindCrypt插件可以发现有base64加密
查看交叉引用 在汇编代码中定位到字串
.text:000000000049B144 mov [rsp+0C8h+var_88], rcx
.text:000000000049B149 mov [rsp+0C8h+var_80], rdi
.text:000000000049B14E mov [rsp+0C8h+var_70], rdx
.text:000000000049B153 lea rcx, BASE64_table_4D9278 ; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm"...
.text:000000000049B15A movzx ebx, byte ptr [rax+rcx+0Bh]
.text:000000000049B15F xor eax, eax
.text:000000000049B161 call runtime_intstring
.text:000000000049B166 mov rcx, [rsp+0C8h+var_88]
.text:000000000049B16B mov rdi, rax
.text:000000000049B16E mov rsi, rbx
.text:000000000049B171 xor eax, eax
.text:000000000049B173 mov rbx, [rsp+0C8h+var_70]
.text:000000000049B178 call runtime_concatstring2
.text:000000000049B17D mov rcx, [rsp+0C8h+var_80]
.text:000000000049B182 inc rcx
.text:000000000049B185 mov rdx, rax
.text:000000000049B188 mov rax, rcx
.text:000000000049B18B mov rcx, rbx
在main的汇编可以找到最后加密对比字符串
mov rcx, rbx
lea rbx, aCpqebacrpNZepY ; "cPQebAcRp+n+ZeP+YePEWfP7bej4YefCYd/7cuP"...
call runtime_memequal
test al, al
jnz short loc_49B282
但是直接解发现是乱码
那么要么换表 要么base64后还进行了加密
但是看密文形式(=) 只可能是换表 但只有上面找到的一处lea ... ABCD...
理论可以动调查看
但IDA动调会直接while(1)卡死
反调试逻辑也比较复杂
这里学习到了用x64dbg的sharpOD插件过掉反调试的方法
搜索安装好插件 把默认勾上的都勾上
在x64中搜索ABCD... 定位到代码段
下个断点 就能运行了
输入flag后一直F9 可以发现出现了一个很大的循环 对base64表进行了变换
0000000000B5B14 | 48:895424 58 | mov qword ptr ss:[rsp+58],rdx | [rsp+58]:"LMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHI"
0000000000B5B15 | 48:8D0D 1EE10300 | lea rcx,qword ptr ds:[B99278] | 0000000000B99278:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
可以发现这里逻辑就是做了一个整体平移 那么提取出变表base64解密即可
DASCTF{73913519-A0A6-5575-0F10-DDCBF50FA8CA}
抽空还得看看具体怎么反调试的 以及IDA怎么反反调试
其实通过这段代码(概率性的F5出来了)
v19 = (unsigned __int8)BASE64_table_4D9278[v25 + 11];
v8 = runtime_intstring(
0,
v19,
(unsigned int)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
v24,
(int)v25 + 11,
v12,
v13,
v14,
v15,
v53,
v59);
LODWORD(v9) = v19;
可以猜到大致是移位11位 外面套了个64的循环 那么应该是取index赋值之类
Blast
用D810稍微去了点混淆
main
__int64 __fastcall main(int a1, char **a2, char **a3)
{
...
v45 = a1;
v44 = a2;
v43 = &v8;
v42 = &v8;
v41 = &v8;
v40 = &v8;
v46 = 0;
s = (char *)(&v8 - 4);
v38 = &v8 - 4;
v37 = &v8 - 24;
v36 = &v8 - 4;
v35 = &v47;
v34 = &v8 - 4;
v9 = HIDWORD(a2);
v8 = 0;
while ( 1 )
{
do
v33 = *v41;
while ( dword_40F9A8 >= 10 && dword_40F9A8 < 10 );
v32 = v33;
do
v31 = strlen((const char *)(unsigned int)a0123456789abcd);
while ( dword_40F9A8 < 10 && dword_40F9A8 >= 10 );
do
v30 = v32 < v31;
while ( dword_40F9A8 < 10 && dword_40F9A8 >= 10 );
if ( !v30 )
break;
do
v29 = *v41;
while ( dword_40F9A8 < 10 && dword_40F9A8 >= 10 );
do
v28 = &a0123456789abcd[v29];
while ( dword_40F9A8 >= 10 && dword_40F9A8 < 10 );
byte_40E060[*v41] = *v28;
do
v27 = *v41;
while ( dword_40F9A8 < 10 && dword_40F9A8 >= 10 );
v26 = v27 + 1;
if ( dword_40F9A8 >= 10 && dword_40F9A8 < 10 )
LABEL_38:
*v41 = v26;
*v41 = v26;
if ( dword_40F9A8 < 10 && dword_40F9A8 >= 10 )
goto LABEL_38;
while ( dword_40F9A8 >= 10 && dword_40F9A8 < 10 )
;
}
v25 = gets(INPUT); // INPUT here
*v40 = 0;
do
LABEL_16:
v24 = *v40;
while ( dword_40F9A8 < 10 && dword_40F9A8 >= 10 );
v23 = v24 < 47;
if ( v24 < 47 )
{
v22 = *v40;
*s = INPUT[v22];
sub_404010(v37); // md5常量初始化
do
{
v21 = 1;
v20 = strlen(s);
}
while ( !((v21 | 1) & (dword_40F9A8 < 10) | ((unsigned __int8)(~(dword_40F9A8 < 10) | v21 ^ 1) ^ (((v21 & 1) == 0) | 0xFE)) & 1) );
if ( dword_40F9A8 < 10 && dword_40F9A8 >= 10 )
goto LABEL_42;
while ( 1 )
{
sub_404140(v37, s, (unsigned int)v20);
sub_40A510(v37, v38);
*v36 = 0;
if ( dword_40F9A8 >= 10 || dword_40F9A8 < 10 )
break;
LABEL_42:
sub_404140(v37, s, (unsigned int)v20);
sub_40A510(v37, v38);
*v36 = 0;
}
while ( 1 )
{
v19 = *v36;
v18 = v19 < 16;
if ( v19 >= 16 )
{
v10 = *v40;
do
v9 = v10 + 1;
while ( dword_40F9A8 < 10 && dword_40F9A8 >= 10 );
*v40 = v9;
goto LABEL_16;
}
v17 = *v36;
v16 = v17;
v15 = *((unsigned __int8 *)v38 + v17);
v14 = 0;
v13 = 16;
v3 = v35;
*(_BYTE *)v35 = byte_40E060[v15 / 16LL];
v4 = v36;
v5 = v34;
*(_BYTE *)v34 = byte_40E060[*((unsigned __int8 *)v38 + *v36) % 16];
v6 = v40;
byte_40E700[33 * *v40 + 2 * *v4] = *(_BYTE *)v3;
byte_40E700[33 * *v6 + 2 * *v4 - (v14 - 1)] = *(_BYTE *)v5;
do
v12 = *v36;
while ( dword_40F9A8 >= 10 && dword_40F9A8 < 10 );
v11 = v12 + 1;
if ( dword_40F9A8 >= 10 && dword_40F9A8 < 10 )
LABEL_44:
*v36 = v11;
*v36 = v11;
if ( dword_40F9A8 < 10 && dword_40F9A8 >= 10 )
goto LABEL_44;
}
}
sub_402370();
return 0LL;
}
看着好多do-while 其实就只执行一次
FindCrypt找到md5加密特征 同时在sub_404010也找到md5常量
再加上找到的
.data:000000000040E0A0 global Big_Numbers1_40E0A0 $c0 b'14d89c38cd0fb23a14be2798d449c182'
.data:000000000040E0C1 global Big_Numbers1_40E0C1 $c0 b'a94837b18f8f43f29448b40a6e7386ba'
.data:000000000040E0E2 global Big_Numbers1_40E0E2 $c0 b'af85d512594fc84a5c65ec9970956ea5'
.data:000000000040E103 global Big_Numbers1_40E103 $c0 b'af85d512594fc84a5c65ec9970956ea5'
.data:000000000040E124 global Big_Numbers1_40E124 $c0 b'10e21da237a4a1491e769df6f4c3b419'
.data:000000000040E145 global Big_Numbers1_40E145 $c0 b'a705e8280082f93f07e3486636f3827a'
.data:000000000040E166 global Big_Numbers1_40E166 $c0 b'297e7ca127d2eef674c119331fe30dff'
.data:000000000040E187 global Big_Numbers1_40E187 $c0 b'b5d2099e49bdb07b8176dff5e23b3c14'
.data:000000000040E1A8 global Big_Numbers1_40E1A8 $c0 b'83be264eb452fcf0a1c322f2c7cbf987'
.data:000000000040E1C9 global Big_Numbers1_40E1C9 $c0 b'a94837b18f8f43f29448b40a6e7386ba'
.data:000000000040E1EA global Big_Numbers1_40E1EA $c0 b'71b0438bf46aa26928c7f5a371d619e1'
.data:000000000040E20B global Big_Numbers1_40E20B $c0 b'a705e8280082f93f07e3486636f3827a'
.data:000000000040E22C global Big_Numbers1_40E22C $c0 b'ac49073a7165f41c57eb2c1806a7092e'
.data:000000000040E24D global Big_Numbers1_40E24D $c0 b'a94837b18f8f43f29448b40a6e7386ba'
.data:000000000040E26E global Big_Numbers1_40E26E $c0 b'af85d512594fc84a5c65ec9970956ea5'
.data:000000000040E28F global Big_Numbers1_40E28F $c0 b'ed108f6919ebadc8e809f8b86ef40b05'
.data:000000000040E2B0 global Big_Numbers1_40E2B0 $c0 b'10e21da237a4a1491e769df6f4c3b419'
.data:000000000040E2D1 global Big_Numbers1_40E2D1 $c0 b'3cfd436919bc3107d68b912ee647f341'
.data:000000000040E2F2 global Big_Numbers1_40E2F2 $c0 b'a705e8280082f93f07e3486636f3827a'
.data:000000000040E313 global Big_Numbers1_40E313 $c0 b'65c162f7c43612ba1bdf4d0f2912bbc0'
.data:000000000040E334 global Big_Numbers1_40E334 $c0 b'10e21da237a4a1491e769df6f4c3b419'
.data:000000000040E355 global Big_Numbers1_40E355 $c0 b'a705e8280082f93f07e3486636f3827a'
.data:000000000040E376 global Big_Numbers1_40E376 $c0 b'3cfd436919bc3107d68b912ee647f341'
.data:000000000040E397 global Big_Numbers1_40E397 $c0 b'557460d317ae874c924e9be336a83cbe'
.data:000000000040E3B8 global Big_Numbers1_40E3B8 $c0 b'a705e8280082f93f07e3486636f3827a'
.data:000000000040E3D9 global Big_Numbers1_40E3D9 $c0 b'9203d8a26e241e63e4b35b3527440998'
.data:000000000040E3FA global Big_Numbers1_40E3FA $c0 b'10e21da237a4a1491e769df6f4c3b419'
.data:000000000040E41B global Big_Numbers1_40E41B $c0 b'f91b2663febba8a884487f7de5e1d249'
.data:000000000040E43C global Big_Numbers1_40E43C $c0 b'a705e8280082f93f07e3486636f3827a'
.data:000000000040E45D global Big_Numbers1_40E45D $c0 b'd7afde3e7059cd0a0fe09eec4b0008cd'
.data:000000000040E47E global Big_Numbers1_40E47E $c0 b'488c428cd4a8d916deee7c1613c8b2fd'
.data:000000000040E49F global Big_Numbers1_40E49F $c0 b'39abe4bca904bca5a11121955a2996bf'
.data:000000000040E4C0 global Big_Numbers1_40E4C0 $c0 b'a705e8280082f93f07e3486636f3827a'
.data:000000000040E4E1 global Big_Numbers1_40E4E1 $c0 b'3cfd436919bc3107d68b912ee647f341'
.data:000000000040E502 global Big_Numbers1_40E502 $c0 b'39abe4bca904bca5a11121955a2996bf'
.data:000000000040E523 global Big_Numbers1_40E523 $c0 b'4e44f1ac85cd60e3caa56bfd4afb675e'
.data:000000000040E544 global Big_Numbers1_40E544 $c0 b'45cf8ddfae1d78741d8f1c622689e4af'
.data:000000000040E565 global Big_Numbers1_40E565 $c0 b'3cfd436919bc3107d68b912ee647f341'
.data:000000000040E586 global Big_Numbers1_40E586 $c0 b'39abe4bca904bca5a11121955a2996bf'
.data:000000000040E5A7 global Big_Numbers1_40E5A7 $c0 b'4e44f1ac85cd60e3caa56bfd4afb675e'
.data:000000000040E5C8 global Big_Numbers1_40E5C8 $c0 b'37327bb06c83cb29cefde1963ea588aa'
.data:000000000040E5E9 global Big_Numbers1_40E5E9 $c0 b'a705e8280082f93f07e3486636f3827a'
.data:000000000040E60A global Big_Numbers1_40E60A $c0 b'23e65a679105b85c5dc7034fded4fb5f'
.data:000000000040E62B global Big_Numbers1_40E62B $c0 b'10e21da237a4a1491e769df6f4c3b419'
.data:000000000040E64C global Big_Numbers1_40E64C $c0 b'71b0438bf46aa26928c7f5a371d619e1'
.data:000000000040E66D global Big_Numbers1_40E66D $c0 b'af85d512594fc84a5c65ec9970956ea5'
.data:000000000040E68E global Big_Numbers1_40E68E $c0 b'39abe4bca904bca5a11121955a2996bf'
找个md5网站解一解 发现是这种形式 md5(md5($pass))
所以这是对单字符做了两遍md5的结果
那么拿到最后数据 爆破一下即可
exp:
s = """
...
"""
s = s.split('\n')
s = s[:-1]
enc = []
for c in s:
enc.append(c[-33:-1])
enc = enc[1:]
from hashlib import md5
flag = ""
for target in enc:
# print(target)
for x in range(32,128):
_hash = md5(str(chr(x)).encode()).hexdigest()
ss = _hash
_hash = md5(str(ss).encode()).hexdigest()
if(_hash == target):
flag += chr(x)
break
print(flag)
# Hello_Ctfer_Velcom_To_my_Mov_and_md5(md5)_world
以上是做题的一些trick 其实还是想了解一下这题完整的逻辑
由于函数不多 挨个翻
在 sub_404CB0 看到是md5加密算法(不可能魔改md5吧...)
交叉引用查看哪里调用了md5
在 sub_404140 找到了唯三调用的点
v14 = *v51 + 24;
v33 = *v51 + 8;
v32 = v14;
sub_404CB0(v33, v14);
*v48 = *(_DWORD *)v46;
while ( 1 )
{
v31 = *v48;
v30 = v31 + 64;
if ( (unsigned int)(v31 + 64) > *(_DWORD *)v49 )
break;
v28 = *v51 + 8;
while ( dword_40FA30 < 10 && dword_40FA30 >= 10 )
;
while ( 1 )
{
sub_404CB0(v28, (char *)*v50 + (unsigned int)*v48);
if ( dword_40FA30 >= 10 || dword_40FA30 < 10 )
break;
sub_404CB0(v28, (char *)*v50 + (unsigned int)*v48);
}
v27 = *v48;
v26 = v27 + 64;
由于第二个第三个在一个虚假的do-while里 实则只执行了第二个md5 加上前面的md5 有效的md5调用了两次
同时通过 v28->v51->v14/v33 也能发现这两次md5有关联 那么合理推测md5(md5(xxx))就很自然了
由于这题控制流不是那么平坦 平坦化后看逻辑还好 但是动调跳来跳去挺烦的 所以动调就免了(以后有时间再来试试)
vm_wo
macos的ARM指令集... 因为没有mac动调不了一点...
题目逻辑简单
输入长度为29的flag后进行虚拟机操作加密 然后与一直enc比对
虚拟机前的opcode准备部分:
do
{
v8[0] = 0x20D01011903001ALL;
*(_QWORD *)((char *)v8 + 7) = 0x300010201180702LL;
BYTE2(v8[0]) = *a1;
interpretBytecode((__int64)v8, 15);
v7[0] = 0x20D02011903001ALL;
*(_QWORD *)((char *)v7 + 7) = 0x400010201180602LL;
BYTE2(v7[0]) = vm_body[0];
interpretBytecode((__int64)v7, 15);
v6[0] = 0x20D03011903001ALL;
*(_QWORD *)((char *)v6 + 7) = 0x500010201180502LL;
BYTE2(v6[0]) = vm_body[0];
interpretBytecode((__int64)v6, 15);
v5[0] = 0x20D04011903001ALL;
*(_QWORD *)((char *)v5 + 7) = 0x600010201180402LL;
BYTE2(v5[0]) = vm_body[0];
interpretBytecode((__int64)v5, 15);
*a1++ = ((unsigned __int8)vm_body[0] >> 5) | (8 * vm_body[0]);
--v2;
}
最开始就是这里没有理解准确
以v7[0]为例
v7[0] = 0x20D02011903001ALL; -> 低8个字节 020D02011903001A
*(_QWORD *)((char *)v7 + 7) = 0x400010201180602LL;
注意到这里是+7 所以会覆盖掉v7[0]的最高字节
->400010201180602 020D02011903001A -> 04000102011806020D02011903001A
刚好15字节
这就是静态分析容易出错的点... 如果能动调的话就特别简单...
然后找对应的opcode(hex)
发现就是一个循环移位+异或的加密逻辑
0 mov vm_body[0] 3
3 mov vm_body[1] vm_body[0]>>1
6 mov vm_body[2] vm_body[0]<<7
9 mov vm_body[0] vm_body[1]|vm_body[2]
12 xor vm_body[0] vm_body[3]
15 mov vm_body[0] 3
18 mov vm_body[1] vm_body[0]>>2
21 mov vm_body[2] vm_body[0]<<6
24 mov vm_body[0] vm_body[1]|vm_body[2]
27 xor vm_body[0] vm_body[4]
30 mov vm_body[0] 3
33 mov vm_body[1] vm_body[0]>>3
36 mov vm_body[2] vm_body[0]<<5
39 mov vm_body[0] vm_body[1]|vm_body[2]
42 xor vm_body[0] vm_body[5]
45 mov vm_body[0] 3
48 mov vm_body[1] vm_body[0]>>4
51 mov vm_body[2] vm_body[0]<<4
54 mov vm_body[0] vm_body[1]|vm_body[2]
57 xor vm_body[0] vm_body[6]
注意下vm_body[3]处是dword的赋值 刚好对应BYTE的[3],[4],[5],[6]
正向爆破即可
DASCTF{you_are_right_so_cool}
EZ加密器
学习到了IDA7.5 Signsrch插件的使用
做的时候犯了一个错误 题目对输入的vericode没有做正确性的检查!!!
只检查了长度... 只要是6位都会继续... 所以后面需要爆破
大致流程:
先输入6位数字 然后base64变表加密得到新的key
再对input做加密 最后HEX拼接与已知比较
比较的密文在加密input的时候做了xor7的修改
关键部分的加密大致可以知道是有sbox的流加密
用IDA插件 Sighsrch
.rdata:0140016080 0040 DES_fp [..64]
.rdata:01400160C0 0030 DES permuted choice key (table) [..48]
.rdata:0140016100 0038 DES permuted choice table (key) [..56]
.rdata:0140016160 0020 DES_p32i [..32]
.rdata:0140016180 0200 DES S-boxes [..512]
.rdata:0140016380 0030 DES_ei [..48]
.rdata:01400163C0 0040 DES initial permutation IP [..64]
知道是DES 那么枚举输入数字爆破即可
from Crypto.Cipher import DES
from base64 import *
from tqdm import *
s1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
s2 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
cipher = bytes.fromhex("0723105D5C12217DCDC3601F5ECB54DA9CCEC2279F1684A13A0D716D17217F4C9EA85FF1A42795731CA3C55D3A4D7BEA")
for i in trange(100000,1000000):
s = str(i).zfill(6)
key = b64encode((s.encode())).decode().translate(str.maketrans(s1,s2)).encode()
des = DES.new(key,DES.MODE_ECB)
pt = des.decrypt(cipher)
if b'DASCTF' in pt:
print(pt)
break
DASCTF{f771b96b71514bb6bc20f3275fa9404e}
标签:Reverse,Big,global,Numbers1,羊城,2023,dword,c0,data From: https://blog.csdn.net/ULGANOY/article/details/137205840