第一步首先想到的是,使用gdb打开,进行动态调试,但是我不知道怎样下断点在程序未运行时,下断点,因为它老是报错::
搜索字符串read:
向上翻一点:
Go语言用IDA根本找不到调用的标准库函数,导致的结果是import窗口一片空白,所以确定核心函数很关键。
由Try again 的错误提示字符串,去winhex或者在IDA的hexdump(在hexview中直接搜索text,也能搜索到)中寻找,相应的字符串,它这个有点奇怪,再去找找正确(correct),竟然找到了:
复制左边的内存地址去,直接jump到指定地址,
还找到了输入的提示信息:
这是寻找成功的赋值代码的步骤,一步步寻找赋值的代码,点击右边黄色引用部分:
这是提示输入的字符Please input you flag like flag{123} to judge::
这个是 Try again! Come on! 的赋值代码,找到字符串数据段的位置时,之后再找到调用的地方:
.text:0000000000495338 lea rax, off_4E1150
sub_4886B0 很可能就是打印函数(不知道为什么这里找不到打印函数),猜测
隔了一段时间,或者在不同的位置按下F5,之后类c代码会有些许的不同,但整体逻辑还是一样
开头4E1130, 成功:4E1140, 失败:4E1150,
v37,v38,v39的赋值,都是这个4A6D00,可能是显示屏的设备号:
*(_QWORD *)&v37 = &unk_4A6D00;
__int64 __fastcall sub_495150(__int64 a1, __int64 a2)
{
__int64 v2; // r8
__int64 v3; // r9
__int128 v4; // ST00_16
__int128 v5; // ST10_16
__int128 v6; // ST20_16
__int64 v7; // r8
__int64 v8; // r9
__int64 v9; // rdx
__int64 v10; // rcx
__int64 v11; // r8
__int64 v12; // r9
__int64 v13; // ST18_8
char v14; // dl
__int128 v15; // ST00_16
__int64 v16; // r8
__int64 v17; // r9
__int64 v18; // r8
__int64 v19; // r9
__int64 v20; // r8
__int64 v21; // r9
__int64 v22; // rdx
__int64 v23; // rbx
__int64 result; // rax
__int64 v25; // rdx
__int64 v26; // r8
__int64 v27; // r9
_QWORD *v28; // [rsp+8h] [rbp-F8h]
char v29; // [rsp+18h] [rbp-E8h]
__int64 v30; // [rsp+20h] [rbp-E0h]
__int64 v31; // [rsp+28h] [rbp-D8h]
__int64 v32; // [rsp+30h] [rbp-D0h]
char v33; // [rsp+58h] [rbp-A8h]
char v34; // [rsp+80h] [rbp-80h]
__int64 v35; // [rsp+98h] [rbp-68h]
_QWORD *v36; // [rsp+A0h] [rbp-60h]
__int128 v37; // [rsp+A8h] [rbp-58h]
__int128 v38; // [rsp+B8h] [rbp-48h]
__int128 v39; // [rsp+C8h] [rbp-38h]
__int128 v40; // [rsp+D8h] [rbp-28h]
__int128 v41; // [rsp+E8h] [rbp-18h]
if ( (unsigned __int64)&v34 <= *(_QWORD *)(__readfsqword(0xFFFFFFF8) + 16) )
sub_44F5B0(a1, a2);
sub_40B290(a1, a2);
v36 = v28;
*(_QWORD *)&v41 = &unk_4A6D00;
*((_QWORD *)&v41 + 1) = &off_4E1130;
sub_4886B0(a1, a2, (__int64)&v41, (__int64)&unk_4A6D00, v2, v3, (__int64)&off_4E28A0, qword_572B18);
*(_QWORD *)&v40 = &unk_4A3E80;
*((_QWORD *)&v40 + 1) = v36;
*(_QWORD *)&v4 = &off_4E2880;
*((_QWORD *)&v4 + 1) = qword_572B10;
*(_QWORD *)&v5 = &unk_4C8569;
*((_QWORD *)&v5 + 1) = 2LL;
*(_QWORD *)&v6 = &v40;
*((_QWORD *)&v6 + 1) = 1LL;
sub_48EB00(a1, a2, (unsigned __int64)&off_4E2880, (__int64)&v40, v7, v8, v4, v5, v6, 1LL);
sub_43F800(a1, a2, v9, v10, v11, v12);
v14 = v13;
*(_QWORD *)&v15 = &v33;
*((_QWORD *)&v15 + 1) = v13;
v29 = v31;
sub_43F660(a1, a2, v14, v31, v16, v17, v15, v30);
sub_47E620(a1, a2, v31, v30, v18, v19, qword_572B00, v30);
v22 = v31;
v23 = v30;
if ( v32 )
{
v35 = v31;
(*(void (__cdecl **)(__int64))(v32 + 24))(a1);
sub_408B40(a1, a2, v25);
*(_QWORD *)&v39 = &unk_4A6D00;
*((_QWORD *)&v39 + 1) = v31;
v29 = 1;
sub_4886B0(a1, a2, (__int64)&off_4E28A0, (__int64)&unk_4A6D00, v26, v27, (__int64)&off_4E28A0, qword_572B18);
v22 = v35;
v23 = v30;
}
if ( v36[1] == v23 && (sub_4023F0(a1, a2, v22, *v36), v29) )
{
*(_QWORD *)&v38 = &unk_4A6D00;
*((_QWORD *)&v38 + 1) = &off_4E1140;
result = sub_4886B0(a1, a2, v22, (__int64)&off_4E28A0, v20, v21, (__int64)&off_4E28A0, qword_572B18);
}
else
{
*(_QWORD *)&v37 = &unk_4A6D00;
*((_QWORD *)&v37 + 1) = &off_4E1150;
result = sub_4886B0(a1, a2, v22, (__int64)&off_4E28A0, v20, v21, (__int64)&off_4E28A0, qword_572B18);
}
return result;
}
需要配置的参数:
先找到虚拟机的ip地址:
找到if语句分叉处,下断点:
动态运行,找到flag:
很奇怪的地方是,为什么,这个地方进行比较的是rax+8 和rbx,但比较的却是却是rdx的值:
64位程序,一边是16个F即64位
这个局部函数的一小段堆栈:
RSP:
000000C000080E90 000000C000088580 debug002:000000C000088580
RBP:
000000C000080F88 000000C000080F90 debug002:000000C000080F90
左上角加载:
debug002:000000C00008A060 db 66h ; f
debug002:000000C00008A061 db 6Ch ; l
debug002:000000C00008A062 db 61h ; a
debug002:000000C00008A063 db 67h ; g
debug002:000000C00008A064 db 7Bh ; {
debug002:000000C00008A065 db 39h ; 9
debug002:000000C00008A066 db 32h ; 2
debug002:000000C00008A067 db 30h ; 0
debug002:000000C00008A068 db 39h ; 9
debug002:000000C00008A069 db 34h ; 4
debug002:000000C00008A06A db 64h ; d
debug002:000000C00008A06B db 61h ; a
debug002:000000C00008A06C db 66h ; f
debug002:000000C00008A06D db 2Dh ; -
debug002:000000C00008A06E db 33h ; 3
debug002:000000C00008A06F db 33h ; 3
debug002:000000C00008A070 db 63h ; c
debug002:000000C00008A071 db 39h ; 9
debug002:000000C00008A072 db 2Dh ; -
debug002:000000C00008A073 db 34h ; 4
debug002:000000C00008A074 db 33h ; 3
debug002:000000C00008A075 db 31h ; 1
debug002:000000C00008A076 db 65h ; e
debug002:000000C00008A077 db 2Dh ; -
debug002:000000C00008A078 db 61h ; a
debug002:000000C00008A079 db 38h ; 8
debug002:000000C00008A07A db 35h ; 5
debug002:000000C00008A07B db 61h ; a
debug002:000000C00008A07C db 2Dh ; -
debug002:000000C00008A07D db 38h ; 8
debug002:000000C00008A07E db 62h ; b
debug002:000000C00008A07F db 66h ; f
debug002:000000C00008A080 db 62h ; b
debug002:000000C00008A081 db 64h ; d
debug002:000000C00008A082 db 35h ; 5
debug002:000000C00008A083 db 64h ; d
debug002:000000C00008A084 db 66h ; f
debug002:000000C00008A085 db 39h ; 9
debug002:000000C00008A086 db 38h ; 8
debug002:000000C00008A087 db 61h ; a
debug002:000000C00008A088 db 64h ; d
debug002:000000C00008A089 db 7Dh ; }
或者Fllow in hex dump:
flag{92094daf-33c9-431e-a85a-8bfbd5df98ad}
动态调试,思路错误,到最后的正确:
text:000000000043D880
11*16
0000000000429B6C 错误跳转
0000000000452B50 退出 sub_452B50
从上往下,越来越接近输出
sub_4886B0
loc_42BB1C
loc_42BAC8
loc_42BB1C
short loc_42BA2B
sub_42B960
loc_42BB1C
loc_42BAC8
short loc_42BA2B
sub_409220
short loc_42FF2C
000000000042F322
000000000042E797
000000000042FF45 双call,第二个跳出函数
000000000042FACC
sub_435590
sub_42E8C0
sub_42E750
sub_42B960
sub_44F380
sub_4886B0
00000000004886B0
sub_42A7F0
000000000044F59A
sub_44F380
000000000042E83B
循环
.text:000000000042E750 mov rcx, fs:0FFFFFFFFFFFFFFF8h
.text:000000000042E759 cmp rsp, [rcx+10h]
000000000042E7D9
sub_44F380
sub_42B960
sub_44F380
#########################################################3
0000000000452C12 //syscall ; LINUX - sys_read
0000000000452BE3 syscall ; LINUX - sys_write
.text:0000000000495338 lea rax, off_4E1150 这个是Try again的赋值代码
没有思路前不要盲目的去做。要先了解程序的语言,再进一步分析。