NewStarCTF2023 WEEK5 RE
这就是 "新生赛" 难度吗??? 。。。
目前也只复现了两道 慢慢补吧~
Fish
隔了好久再来看熟练多了
IDA打开 main啥都没有
看汇编
大量的这种类型的花指令
.text:0000000000401A12 jz short near ptr loc_401A16+1
.text:0000000000401A14 jnz short near ptr loc_401A16+1
以前我的做法是将这两个全部patch掉 但这种只适用于一两个这种❀的情况
如果有很多的话这种patch会影响到IDA对后续语句的识别 比如这题如果这么patch那么关键常量就找不到了
正确做法是将jnz后的那个指令字节patch为nop(90)
为了方便批量化操作 general打开操作码显示
.text:0000000000401A12 74 03 jz short near ptr loc_401A16+1
.text:0000000000401A14 75 01 jnz short near ptr loc_401A16+1
.text:0000000000401A16
当我们识别到 74 75 后将之后的位置设为90即可
start = 0x4019FC
end = 0x401AD8
while start<end:
if((get_wide_byte(start)==0x74) and (get_wide_byte(start+2)==0x75)):
ida_bytes.patch_byte(start+4,0x90)
start += 1
print("[+] OK !")
这样patch后再将main全部选中按C Force一下就可以得到正常的源码了
这样的话汇编大致是这种形式
.text:0000000000401A17 ; sub_4019FE+16↑j
.text:0000000000401A17 48 B8 4E 65 77 53 74 61 mov rax, 7261745377654Eh
.text:0000000000401A17 72 00
.text:0000000000401A21 48 89 45 10 mov [rbp+30h+var_20], rax
.text:0000000000401A25 74 03 jz short loc_401A2A
.text:0000000000401A27 75 01 jnz short loc_401A2A
.text:0000000000401A29 90 nop
可以看到这里mov rax ... 这里的值就是 NewStar
这是最初patch会影响到的语句块!
然后main是这个样子
// positive sp value has been detected, the output may be wrong!
__int64 __fastcall sub_4019FE(__int64 a1, __int64 a2, __int64 a3)
{
char Str1[96]; // [rsp+20h] [rbp-60h] BYREF
int v5; // [rsp+80h] [rbp+0h]
int v6; // [rsp+84h] [rbp+4h] BYREF
__int64 v7[4]; // [rsp+90h] [rbp+10h] BYREF
sub_402660(a1, a2, a3);
v7[0] = 0x7261745377654Ei64;
memset(Str1, 0, sizeof(Str1));
v5 = 0;
sub_401951(0i64, &v6);
scanf("%s", Str1);
sub_4016C1(v7);
((void (__fastcall *)(char *))sub_40188B)(Str1);
if ( !strcmp(Str1, &Str2) )
puts("WOW!");
else
puts("I believe you can do it!");
system("pause");
return 0i64;
}
用FindCrypt插件Ctrl+F一看发现是BlowFish加密
在strcmp那儿可以拿到check值 key猜测是 "NewStar"
找个在线网站解就完了
注意选择 nopadding
flag : flag{YouGotit!!Yougoit!!!!TheFifthPZGALAXYLEVEL}
其实最后发现可以将整个程序按照这种patch处理后Force一下能看到完整程序流
MAIN
int __fastcall MAIN(int argc, const char **argv, const char **envp)
{
char Str1[96]; // [rsp+20h] [rbp-60h] BYREF
int v5; // [rsp+80h] [rbp+0h]
__int64 v6[4]; // [rsp+90h] [rbp+10h] BYREF
sub_402660(argc, argv, envp);
v6[0] = 0x7261745377654Ei64;
memset(Str1, 0, sizeof(Str1));
v5 = 0;
sub_401951();
scanf("%s", Str1);
sub_4016C1((const char *)v6);
sub_40188B(Str1);
if ( !strcmp(Str1, (const char *)&loc_40403F + 1) )
puts("WOW!");
else
puts("I believe you can do it!");
system("pause");
return 0;
}
sub_4016C1 应该就是根据NewStar来生成后续密钥
char *__fastcall sub_4016C1(const char *a1)
{
char *result; // rax
int v2; // [rsp+24h] [rbp-1Ch] BYREF
int v3; // [rsp+28h] [rbp-18h] BYREF
int v4; // [rsp+2Ch] [rbp-14h]
int v5; // [rsp+30h] [rbp-10h]
int v6; // [rsp+34h] [rbp-Ch]
int i; // [rsp+38h] [rbp-8h]
int j; // [rsp+3Ch] [rbp-4h]
result = (char *)strlen(a1);
v4 = (int)result;
v5 = 0;
j = 0;
v6 = 0;
while ( j <= 17 )
{
v5 = 0;
for ( i = 0; i <= 3; ++i )
{
v5 = (v5 << 8) | (unsigned __int8)a1[v6];
v6 = (v6 + 1) % v4;
}
result = (char *)&loc_40407F + 1;
*(_DWORD *)((char *)&loc_40407F + 4 * j++ + 1) ^= v5;
}
v3 = 0;
v2 = 0;
for ( j = 0; j <= 17; j += 2 )
{
sub_4015DE(&v3, &v2);
*(_DWORD *)((char *)&loc_40407F + 4 * j + 1) = v3;
result = (char *)&loc_40407F + 1;
*(_DWORD *)((char *)&loc_40407F + 4 * j + 5) = v2;
}
for ( j = 0; j <= 3; ++j )
{
for ( i = 0; i <= 255; i += 2 )
{
sub_4015DE(&v3, &v2);
*(_DWORD *)((char *)&loc_4040FF + 1024 * (__int64)j + 4 * i + 1) = v3;
result = (char *)&loc_4040FF + 1;
*(_DWORD *)((char *)&loc_4040FF + 1024 * (__int64)j + 4 * i + 5) = v2;
}
}
return result;
}
sub_40188B 标准BlowFish加密
__int64 __fastcall sub_40188B(const char *a1)
{
_DWORD *v1; // rbx
__int64 result; // rax
unsigned int v3; // [rsp+24h] [rbp-5Ch] BYREF
unsigned int v4; // [rsp+28h] [rbp-58h] BYREF
int v5; // [rsp+2Ch] [rbp-54h]
char *v6; // [rsp+30h] [rbp-50h]
unsigned int i; // [rsp+3Ch] [rbp-44h]
v5 = strlen(a1) / 8;
v6 = (char *)a1;
for ( i = 0; ; ++i )
{
result = i;
if ( (int)i >= v5 )
break;
v4 = sub_403000(*(unsigned int *)v6);
v3 = sub_403000(*((unsigned int *)v6 + 1));
sub_4015DE(&v4, &v3);
*(_DWORD *)v6 = sub_403000(v4);
v1 = v6 + 4;
*v1 = sub_403000(v3);
v6 += 8;
}
return result;
}
在sub_4015DE中可以看到BlowFish的常量 0x9216D5D9 和 0x8979FB1B(dword_4040C4)
unsigned int *__fastcall sub_4015DE(unsigned int *a1, unsigned int *a2)
{
unsigned int *result; // rax
unsigned int v3; // [rsp+28h] [rbp-8h]
unsigned int v4; // [rsp+28h] [rbp-8h]
int i; // [rsp+2Ch] [rbp-4h]
for ( i = 0; i <= 15; ++i )
{
*a1 ^= *(_DWORD *)((char *)&loc_40407F + 4 * i + 1);
*a2 ^= sub_401530(*a1);
v3 = *a1;
*a1 = *a2;
*a2 = v3;
}
v4 = *a1;
*a1 = *a2;
*a2 = v4;
*a2 ^= 0x9216D5D9;
result = a1;
*a1 ^= dword_4040C4;
return result;
}
Genshin
考察的是erlang beam文件逆向
先下载好erlang编译器工具
然后通过这种方式(搜了一圈也不知道怎么找到这条反汇编命令的...)
io:format("~p~n",[beam_disasm:file("genshin.beam")]).
注意结尾要有'.' !!!
可以得到文件的字节码
{beam_file,genshin,
[{main,1,2},{module_info,0,11},{module_info,1,13}],
[{vsn,[294325075297162417208450880208266398775]}],
[{version,"8.3.1"},
{options,[]},
{source,
[47,109,110,116,47,100,47,67,84,70,47,20986,39064,47,50,48,50,51,45,
56,45,100,117,105,110,101,105,115,97,105,47,103,101,110,115,104,105,
110,46,101,114,108]}],
[{function,main,1,2,
[{label,1},
{line,1},
{func_info,{atom,genshin},{atom,main},1},
{label,2},
{test,is_nonempty_list,{f,3},[{x,0}]},
{get_list,{x,0},{x,1},{x,0}},
{test,is_nil,{f,3},[{x,0}]},
{move,{x,1},{x,0}},
{call_only,1,{genshin,check,1}},
{label,3},
{move,
{literal,"Usage: xxxxxxxx genshin.beam <input_string>~n"},
{x,0}},
{line,2},
{call_ext_only,1,{extfunc,io,format,1}}]},
{function,check,1,5,
[{line,3},
{label,4},
{func_info,{atom,genshin},{atom,check},1},
{label,5},
{test,is_list,{f,4},[{x,0}]},
{allocate,1,1},
{move,{x,0},{y,0}},
{move,{literal,[21407,31070,46,46,46,126,110]},{x,0}},
{line,4},
{call_ext,1,{extfunc,io,format,1}},
{move,{integer,1},{x,1}},
{move,nil,{x,2}},
{move,{y,0},{x,0}},
{init_yregs,{list,[{y,0}]}},
{line,5},
{call,3,{genshin,transform,3}},
{line,6},
{call_ext,1,{extfunc,erlang,list_to_binary,1}},
{test,is_eq_exact,
{f,6},
[{tr,{x,0},{t_bitstring,8,false}},
{literal,
<<107,114,102,103,130,68,118,106,107,119,88,109,131,70,
114,130,122,81,111,40,107,77,76,38,52,73,72,101>>}]},
{move,{literal,[21551,21160,65281,126,110]},{x,0}},
{line,7},
{call_ext_last,1,{extfunc,io,format,1},1},
{label,6},
{move,{literal,[20851,38381,126,110]},{x,0}},
{line,8},
{call_ext_last,1,{extfunc,io,format,1},1}]},
{function,transform,3,8,
[{line,9},
{label,7},
{func_info,{atom,genshin},{atom,transform},3},
{label,8},
{test,is_nonempty_list,{f,9},[{x,0}]},
{get_list,{x,0},{x,3},{x,0}},
{line,10},
{gc_bif,'bxor',
{f,0},
4,
[{x,3},{tr,{x,1},{t_integer,{1,'+inf'}}}],
{x,3}},
{gc_bif,'+',{f,0},4,[{tr,{x,3},{t_integer,any}},{integer,4}],{x,3}},
{line,11},
{gc_bif,'+',
{f,0},
4,
[{tr,{x,1},{t_integer,{1,'+inf'}}},{integer,1}],
{x,1}},
{test_heap,2,4},
{put_list,{x,3},{x,2},{x,2}},
{call_only,3,{genshin,transform,3}},
{label,9},
{test,is_nil,{f,7},[{x,0}]},
{move,{x,2},{x,0}},
{line,9},
{call_ext_only,1,{extfunc,lists,reverse,1}}]},
{function,module_info,0,11,
[{line,0},
{label,10},
{func_info,{atom,genshin},{atom,module_info},0},
{label,11},
{move,{atom,genshin},{x,0}},
{call_ext_only,1,{extfunc,erlang,get_module_info,1}}]},
{function,module_info,1,13,
[{line,0},
{label,12},
{func_info,{atom,genshin},{atom,module_info},1},
{label,13},
{move,{x,0},{x,1}},
{move,{atom,genshin},{x,0}},
{call_ext_only,2,{extfunc,erlang,get_module_info,2}}]}]}
慢慢分析字节码吧...
这里是最后的check is_eq_exact
{test,is_eq_exact,
{f,6},
[{tr,{x,0},{t_bitstring,8,false}},
{literal,
<<107,114,102,103,130,68,118,106,107,119,88,109,131,70,
114,130,122,81,111,40,107,77,76,38,52,73,72,101>>}]},
接着往前找到transform函数
在网上搜了搜beam字节码 找到一些例子
{gc_bif,abs,{f,0},2,[{x,0}],{x,0}}. //用x0去调用bif函数abs,存储结果到x0寄存器,
{gc_bif,abs,{f,0},2,[{x,1}],{x,1}}. //用x1去调用bif函数abs,存储结果到x1寄存器,
{gc_bif,'+',{f,0},2,[{x,0},{x,1}],{x,0}}. //执行bif函数+, x0+x1,结果放入x0寄存器
有了这些例子再看transform
{function,transform,3,8,
[{line,9},
{label,7},
{func_info,{atom,genshin},{atom,transform},3},
{label,8},
{test,is_nonempty_list,{f,9},[{x,0}]},
{get_list,{x,0},{x,3},{x,0}},
{line,10},
{gc_bif,'bxor',
{f,0},
4,
[{x,3},{tr,{x,1},{t_integer,{1,'+inf'}}}],
{x,3}},
{gc_bif,'+',{f,0},4,[{tr,{x,3},{t_integer,any}},{integer,4}],{x,3}},
{line,11},
{gc_bif,'+',
{f,0},
4,
[{tr,{x,1},{t_integer,{1,'+inf'}}},{integer,1}],
{x,1}},
{test_heap,2,4},
{put_list,{x,3},{x,2},{x,2}},
{call_only,3,{genshin,transform,3}},
{label,9},
{test,is_nil,{f,7},[{x,0}]},
{move,{x,2},{x,0}},
{line,9},
{call_ext_only,1,{extfunc,lists,reverse,1}}]},
重点在这一部分:
{line,10},
{gc_bif,'bxor',
{f,0},
4,
[{x,3},{tr,{x,1},{t_integer,{1,'+inf'}}}],
{x,3}},
{gc_bif,'+',{f,0},4,[{tr,{x,3},{t_integer,any}},{integer,4}],{x,3}},
{line,11},
{gc_bif,'+',
{f,0},
4,
[{tr,{x,1},{t_integer,{1,'+inf'}}},{integer,1}],
{x,1}},
bxor这里:
{gc_bif,'bxor',
{f,0},
4,
[{x,3},{tr,{x,1},{t_integer,{1,'+inf'}}}],
{x,3}},
大致是 {x,1} xor (t_integer+1) 然后结果存给 {x,3}
再看下面的'+':
{gc_bif,'+',{f,0},4,[{tr,{x,3},{t_integer,any}},{integer,4}],{x,3}},
这里是 {x,3}+4这种运算 最后结果存回 {x,3}
再下面的'+'应该是循环的ecx++
所以加密逻辑:
flag[i] = (flag[i]^(i+1))+4
从enc[]逆回去即可得到flag
flag: flag{Funny_erLang_x0r__😃__} (神奇的博客园把 ': )'给编译成这个emoji...)
这种搜索资料的能力和通过例子学习新知识的能力也要多培养 练习
不得不感慨赛时做出了的3位佬tql orz