go语言函数堆栈
运行程序,这题输入的格式为flag{xxxxx},两种方式:一种输入做加密与固定值比,一种固定值加密与输入比,这题是后者
遇到go语言先file一下,发现去符号了
ida golang helper后
先搜字符串,没有什么发现,说明关键字符串被加密了,看imports,也没有什么发现
分析main_main函数
输入后对某变量base64,程序结尾的==和memcmp,而且每个分支都有print函数,猜测这里为关键点进行分析,整理伪代码如下
__int64 __fastcall main_main(__int64 a1, __int64 a2)
{
__int64 v2; // r8
__int64 v3; // r9
__int64 v4; // r8
__int64 v5; // r9
__int64 v6; // rdx
__int64 v7; // rcx
__int64 v8; // r8
__int64 v9; // r9
__int64 v10; // rdx
int v11; // er8
__int64 v12; // r8
__int64 v13; // r9
__int64 v14; // r8
__int64 v15; // r9
const __m128i *v16; // rdx
unsigned __int64 v17; // rbx
__int64 result; // rax
__int64 v19; // rdx
__int64 v20; // r8
__int64 v21; // r9
__int128 v22; // [rsp+0h] [rbp-100h]
__int128 v23; // [rsp+0h] [rbp-100h]
__int64 *v24; // [rsp+8h] [rbp-F8h]
__int128 v25; // [rsp+10h] [rbp-F0h]
__int64 v26; // [rsp+10h] [rbp-F0h]
__int64 v27; // [rsp+18h] [rbp-E8h]
char v28; // [rsp+18h] [rbp-E8h]
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]
const __m128i *v35; // [rsp+98h] [rbp-68h]
__int64 *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) )
runtime_morestack_noctxt(a1, a2);
runtime_newobject(a1, a2);
v36 = v24;
*(_QWORD *)&v41 = &unk_4A6D00;
*((_QWORD *)&v41 + 1) = &off_4E1130;
fmt_Fprintln(a1, a2, (__int64)&v41, (__int64)&unk_4A6D00, v2, v3, (__int64)&off_4E28A0, qword_572B18);
*(_QWORD *)&v40 = &unk_4A3E80;
*((_QWORD *)&v40 + 1) = v36;
*(_QWORD *)&v22 = &off_4E2880;
*((_QWORD *)&v22 + 1) = qword_572B10;
*(_QWORD *)&v25 = &unk_4C8569;
*((_QWORD *)&v25 + 1) = 2LL;
fmt_Fscanf(a1, a2, (unsigned __int64)&off_4E2880, (__int64)&v40, v4, v5, v22, v25, (unsigned __int64)&v40, 1LL, 1LL);
runtime_stringtoslicebyte(a1, a2, v6, v7, v8, v9);
v10 = v27;
*(_QWORD *)&v23 = &v33;
*((_QWORD *)&v23 + 1) = v27;
v28 = v31;
runtime_slicebytetostring(a1, a2, v10, v31, v11, v23);
encoding_base64__ptr_Encoding_DecodeString(a1, a2, v31, v30, v12, v13, qword_572B00, v30, v31);
v16 = (const __m128i *)v31;
v17 = v30;
if ( v32 )
{
v35 = (const __m128i *)v31;
(*(void (__fastcall **)(__int64))(v32 + 24))(a1);
runtime_convTstring(a1, a2, v19);
*(_QWORD *)&v39 = &unk_4A6D00;
*((_QWORD *)&v39 + 1) = v26;
v28 = 1;
fmt_Fprintln(a1, a2, (__int64)&off_4E28A0, (__int64)&unk_4A6D00, v20, v21, (__int64)&off_4E28A0, qword_572B18);
v16 = v35;
v17 = v30;
}
if ( v36[1] == v17
&& (runtime_memequal(a1, a2, (__int64)v16, *v36, v14, v15, v16, (const __m128i *)*v36, v17, v28), v29) )
{
*(_QWORD *)&v38 = &unk_4A6D00;
*((_QWORD *)&v38 + 1) = &off_4E1140;
result = fmt_Fprintln(a1, a2, (__int64)v16, (__int64)&off_4E28A0, v14, v15, (__int64)&off_4E28A0, qword_572B18);
}
else
{
*(_QWORD *)&v37 = &unk_4A6D00;
*((_QWORD *)&v37 + 1) = &off_4E1150;
result = fmt_Fprintln(a1, a2, (__int64)v16, (__int64)&off_4E28A0, v14, v15, (__int64)&off_4E28A0, qword_572B18);
}
return result;
}
由储备知识盲猜 (__int64)&off_4E2880是输入存储的地址, (__int64)&v40是输入的长度,剩下的不太好分析,那么就动态分析
输入123456789abcdefg 0x10个数
想找输入存的位置,但不好找,写了个脚本想在栈里找输入,失败了,在debug段里找输入,成功了,第一次用debug段,留个坑
调试发现debug,stack,vvar,vdso,vsyscall段在调试后出现的
#debug002段开始地址
begin = 0xC000000000
end = 0xC000200000
x = end-begin
for i in range(1,x-1):
addr = begin+i
if(Byte(addr-1) == 0x39 and Byte(addr) == 0x61 and Byte(addr+1) == 0x62 and Byte(addr+2) == 0x63 and Byte(addr+3) == 0x64 and Byte(addr+4) == 0x65 and Byte(addr+5) == 0x66):
print(hex(addr))
注意到flag{92094daf-33c9-431e-a85a-8bfbd5df98ad}也是在debug段
flag{92094daf-33c9-431e-a85a-8bfbd5df98ad}
经过几次调试,debug段存储的应该是在动态调试中所有新出现的信息
比较有意思的几个点:
以后做题过程中,可以考虑一下debug段的信息