Reverse
flat
flat_bdc004aa1104e443b3b9c90a6b98d5e6.zip
初步阅读f5代码,发现程序是由大量switch语句构成的,其中每个case都套上了很奇怪的数字,不方便静态阅读,所以我采取了动态调试的方式
发现大量诸如以下的语句
00040109E loc_40109E: ; CODE XREF: main:loc_4013B3↓j
.text:000000000040109E mov eax, [rbp+var_154]
.text:00000000004010A4 mov ecx, eax
.text:00000000004010A6 sub ecx, 88070986h
.text:00000000004010AC mov [rbp+var_164], eax
.text:00000000004010B2 mov [rbp+var_168], ecx
.text:00000000004010B8 jz loc_401270
.text:00000000004010BE jmp $+5
.text:00000000004010C3 ; ---------------------------------------------------------------------------
.text:00000000004010C3
.text:00000000004010C3 loc_4010C3: ; CODE XREF: main+7E↑j
.text:00000000004010C3 mov eax, [rbp+var_164]
.text:00000000004010C9 sub eax, 916CBF8Ch
.text:00000000004010CE mov [rbp+var_16C], eax
.text:00000000004010D4 jz loc_401382
.text:00000000004010DA jmp $+5
动态调试后可知程序把大量的汇编代码通过这样的方式混淆了,然后再通过操作码来读取对应的功能。
000401270 loc_401270: ; CODE XREF: main+78↑j
.text:0000000000401270 lea rdi, [rbp+s]
.text:0000000000401274 mov rax, offset aJ ; "J"
.text:000000000040127E mov ecx, 90h
.text:0000000000401283 mov edx, ecx ; n
.text:0000000000401285 lea rsi, [rbp+dest]
.text:000000000040128C mov [rbp+var_198], rdi
.text:0000000000401293 mov rdi, rsi ; dest
.text:0000000000401296 mov rsi, rax ; src
.text:0000000000401299 call _memcpy
.text:000000000040129E mov rdi, [rbp+var_198] ; char *
.text:00000000004012A5 call _Z10fun_check1Pc ; fun_check1(char *)
.text:00000000004012AA mov ecx, 916CBF8Ch
.text:00000000004012AF mov r8d, 70B25450h
.text:00000000004012B5 test al, 1
.text:00000000004012B7 cmovnz ecx, r8d
.text:00000000004012BB mov [rbp+var_154], ecx
.text:00000000004012C1 jmp loc_4013B3
.text:00000000004012C6 ; ---------------------------------------------------------------------------
.text:00000000004012C6
.text:00000000004012C6 loc_4012C6: ; CODE XREF: main+190↑j
.text:00000000004012C6 lea rdi, [rbp+s] ; char *
.text:00000000004012CA call _Z10fun_check2Pc ; 检测格式
.text:00000000004012CF mov ecx, 916CBF8Ch
.text:00000000004012D4 mov edx, 48DC1E73h
.text:00000000004012D9 test al, 1
.text:00000000004012DB cmovnz ecx, edx
.text:00000000004012DE mov [rbp+var_154], ecx
.text:00000000004012E4 jmp loc_4013B3
.text:00000000004012E9 ; ---------------------------------------------------------------------------
.text:00000000004012E9
.text:00000000004012E9 loc_4012E9: ; CODE XREF: main+174↑j
.text:00000000004012E9 lea rdi, [rbp+s] ; char *
.text:00000000004012ED call _Z10fun_check3Pc ; 限制格式
.text:00000000004012F2 mov ecx, 916CBF8Ch
.text:00000000004012F7 mov edx, 9FDEA8ECh
.text:00000000004012FC test al, 1
.text:00000000004012FE cmovnz ecx, edx
.text:0000000000401301 mov [rbp+var_154], ecx
.text:0000000000401307 jmp loc_4013B3
.text:000000000040130C ; ---------------------------------------------------------------------------
.text:000000000040130C
.text:000000000040130C loc_40130C: ; CODE XREF: main+B0↑j
.text:000000000040130C lea rdi, [rbp+s] ; char *
.text:0000000000401310 call _Z10fun_check4Pc ; 检查格式
.text:0000000000401315 mov ecx, 916CBF8Ch
.text:000000000040131A mov edx, 0CDC4B0D0h
.text:000000000040131F test al, 1
.text:0000000000401321 cmovnz ecx, edx
.text:0000000000401324 mov [rbp+var_154], ecx
.text:000000000040132A jmp loc_4013B3
.text:000000000040132F ; ---------------------------------------------------------------------------
.text:000000000040132F
.text:000000000040132F loc_40132F: ; CODE XREF: main+104↑j
.text:000000000040132F lea rsi, [rbp+dest] ; int *
.text:0000000000401336 lea rdi, [rbp+var_B0] ; char *
.text:000000000040133D call _Z10fun_check5PcPi ; fun_check5(char *,int *)
.text:0000000000401342 mov ecx, 916CBF8Ch
.text:0000000000401347 mov edx, 0F465F43Bh
.text:000000000040134C test al, 1
.text:000000000040134E cmovnz ecx, edx
.text:0000000000401351 mov [rbp+var_154], ecx
.text:0000000000401357 jmp loc_4013B3
check1~5是整个程序的核心部分,其中check1 ~check4都是对flag格式的限制
我们只需要将call checkx 打上断点,在这个call执行完成之后,观察al的值即可判断格式是否符合要求,最终发现flag的格式是flag{},总长度共42.
最重要的是check5函数,其中
.text:0000000000400D90 loc_400D90: ; CODE XREF: fun_check5(char *,int *)+E9↑j
.text:0000000000400D90 mov eax, 0B92BF994h
.text:0000000000400D95 mov ecx, 0AC151DE7h
.text:0000000000400D9A mov rdx, [rbp+var_10]
.text:0000000000400D9E movsxd rsi, [rbp+var_E4]
.text:0000000000400DA5 movsx edi, byte ptr [rdx+rsi] ; 读取下一个字符
.text:0000000000400DA9 cmp edi, 30h
.text:0000000000400DAC cmovge eax, ecx
.text:0000000000400DAF mov [rbp+var_E8], eax
.text:0000000000400DB5 jmp loc_40102D
.text:0000000000400DBA ; ---------------------------------------------------------------------------
.text:0000000000400DBA
.text:0000000000400DBA loc_400DBA: ; CODE XREF: fun_check5(char *,int *)+79↑j
.text:0000000000400DBA mov eax, 0B92BF994h
.text:0000000000400DBF mov ecx, 0E37ECC40h
.text:0000000000400DC4 mov rdx, [rbp+var_10]
.text:0000000000400DC8 movsxd rsi, [rbp+var_E4]
.text:0000000000400DCF movsx edi, byte ptr [rdx+rsi]
.text:0000000000400DD3 cmp edi, 39h ; 判断是否为数字
.text:0000000000400DD6 cmovle eax, ecx
.text:0000000000400DD9 mov [rbp+var_E8], eax
.text:0000000000400DDF jmp loc_40102D
.text:0000000000400DE4 ; ---------------------------------------------------------------------------
.text:0000000000400DE4
.text:0000000000400DE4 loc_400DE4: ; CODE XREF: fun_check5(char *,int *)+159↑j
.text:0000000000400DE4 mov rax, [rbp+var_10]
.text:0000000000400DE8 movsxd rcx, [rbp+var_E4]
.text:0000000000400DEF movsx edx, byte ptr [rax+rcx]
.text:0000000000400DF3 sub edx, 1D854A80h
.text:0000000000400DF9 add edx, 11h
.text:0000000000400DFC add edx, 1D854A80h
.text:0000000000400E02 movsxd rax, [rbp+var_E4]
.text:0000000000400E09 mov [rbp+rax*4+var_E0], edx
.text:0000000000400E10 mov [rbp+var_E8], 72D256E3h
.text:0000000000400E1A jmp loc_40102D
如果输入是数字,就将数字转换为对应的大写字母
.text:0000000000400E1F loc_400E1F: ; CODE XREF: fun_check5(char *,int *)+B1↑j
.text:0000000000400E1F mov eax, 966647E9h
.text:0000000000400E24 mov ecx, 0BA6BE5FDh
.text:0000000000400E29 mov rdx, [rbp+var_10]
.text:0000000000400E2D movsxd rsi, [rbp+var_E4]
.text:0000000000400E34 movsx edi, byte ptr [rdx+rsi]
.text:0000000000400E38 cmp edi, 2Dh
.text:0000000000400E3B cmovz eax, ecx
.text:0000000000400E3E mov [rbp+var_E8], eax
.text:0000000000400E44 jmp loc_40102D
'-'符号不作处理
.text:0000000000400E75 loc_400E75: ; CODE XREF: fun_check5(char *,int *)+41↑j
.text:0000000000400E75 mov eax, 67B6BD28h
.text:0000000000400E7A mov ecx, 0B80842FBh
.text:0000000000400E7F mov rdx, [rbp+var_10]
.text:0000000000400E83 movsxd rsi, [rbp+var_E4]
.text:0000000000400E8A movsx edi, byte ptr [rdx+rsi]
.text:0000000000400E8E cmp edi, 61h
.text:0000000000400E91 cmovge eax, ecx
.text:0000000000400E94 mov [rbp+var_E8], eax
.text:0000000000400E9A jmp loc_40102D
.text:0000000000400E9F ; ---------------------------------------------------------------------------
.text:0000000000400E9F
.text:0000000000400E9F loc_400E9F: ; CODE XREF: fun_check5(char *,int *)+95↑j
.text:0000000000400E9F mov eax, 67B6BD28h
.text:0000000000400EA4 mov ecx, 7CFC4F40h
.text:0000000000400EA9 mov rdx, [rbp+var_10]
.text:0000000000400EAD movsxd rsi, [rbp+var_E4]
.text:0000000000400EB4 movsx edi, byte ptr [rdx+rsi]
.text:0000000000400EB8 cmp edi, 7Ah
.text:0000000000400EBB cmovle eax, ecx
.text:0000000000400EBE mov [rbp+var_E8], eax
.text:0000000000400EC4 jmp loc_40102D
.text:0000000000400EC9 ; ---------------------------------------------------------------------------
.text:0000000000400EC9
.text:0000000000400EC9 loc_400EC9: ; CODE XREF: fun_check5(char *,int *)+271↑j
.text:0000000000400EC9 mov rax, [rbp+var_10]
.text:0000000000400ECD movsxd rcx, [rbp+var_E4]
.text:0000000000400ED4 movsx edx, byte ptr [rax+rcx]
.text:0000000000400ED8 sub edx, 50577E63h
.text:0000000000400EDE sub edx, 30h
.text:0000000000400EE1 add edx, 50577E63h
.text:0000000000400EE7 movsxd rax, [rbp+var_E4]
.text:0000000000400EEE mov [rbp+rax*4+var_E0], edx
.text:0000000000400EF5 mov [rbp+var_E8], 67B6BD28h
.text:0000000000400EFF jmp loc_40102D
如果是字母就转换为数字
最后在转换完成的字符串上面下一个内存断点,就可找到这个字符串与目标加密字符串比较的过程
加密字符串:
flag{J2261C63-3I2I-EGE4-IBCC-IE41A5I5F4HB}
解密即可。
en c = "J2261C63-3I2I-EGE4-IBCC-IE41A5I5F4HB"
flag = "flag{"
for c in enc:
if c == '-':
fuck = 0
elif c >= 'A' and c <= 'J':
c = chr(ord(c) - 0x11)
else:
c = chr(ord(c) + 48)
flag = flag + c
flag += '}'
print(flag)
src_leak
src_leak_2886f9ce0464ae67bbeb52d939c9979d.zip
没学过c++语法,看这些东西看蒙了
就大概猜了一下,发现算法流程并不是很复杂
x1~x5都是用一个函数跑出来的
x6用另一个
cout << func3< func2<x1> > << endl;
cout << func3< func2<x2> > << endl;
cout << func3< func2<x3> > << endl;
cout << func3< func2<x4> > << endl;
cout << func3< func2<x5> > << endl;
// output: 1 1 1 1 1
cout << _func1<x1>::result << endl;
cout << _func1<x2>::result << endl;
cout << _func1<x3>::result << endl;
cout << _func1<x4>::result << endl;
cout << _func1<x5>::result << endl;
//output: 963 4396 6666 1999 3141
说几个比较关键的地方
template <bool Flag, class MaybeA, class MaybeB> class IfElse;
template <class MaybeA, class MaybeB>
class IfElse<true, MaybeA, MaybeB> {
public:
using ResultType = MaybeA;
};
template <class MaybeA, class MaybeB>
class IfElse<false, MaybeA, MaybeB> {
public:
using ResultType = MaybeB;
看起来这么大一堆,实际上就表达了一个意思
result = flag ? MaybeA:MaybeB
template <uint N, uint L> struct func1<N, L, L> { enum { result = L }; };
template<>
constexpr size_t func2<0> = 0;
template<uint m>struct TEST<0, m> {
const static uint value = 0;
};
template<uint n>struct TEST<n, 0> {
const static uint value = 1;
};
template<>struct func4<1> {
const static uint value = 0;
};
template<>struct func4<2> {
const static uint value = 1;
};
以上是各个函数的边界条件,一定不能省略,否则跑不出来或者跑出来不对,尤其是func4的1和2
因为c的执行效率比较高,抱着试一试的心态,写了个暴力算法进行求解,在int范围下尝试失败(因为涉及到了数据的平方,int类型会溢出),于是更换为long long 进行求解,虽然效率不高,但还是可以在十秒中左右得出结果。
#include<cstdio>
typedef long long LL;
LL func2(LL n){
if(n==0) return 0;
return n%2 + func2(n/2);
}
LL func3(LL n){
return n%2;
}
LL func1(LL n, LL l, LL r){
if(l==r) return l;
LL mid = (l+r+1)/2;
if(n < mid*mid)
return func1(n,l,mid-1);
else
return func1(n,mid,r);
}
LL _func1(LL n){
return func1(n,1,n);
}
LL nextn(LL n, LL m){
return ((n % m != 0) * n);
}
LL nextm(LL n, LL m){
return (m * m <= n ? (m + 1) : 0);
}
LL test(LL n,LL m){
if(n == 0) return 0;
if(m == 0) return 1;
return test(nextn(n,m) , nextm(n,m));
}
LL func4(LL n){
if(n==1) return 0;
if(n==0) return 1;
return test(n,2);
}
int main(){
/************
x1 ~ x5
//input: 963 4396 6666 1999 3141
// ans = 1927 8792 13332 3998 6282
**********/
LL input[] = {963,4396,6666,1999,3141};
printf("flag{");
for(LL j = 0; j<=4 ; j++){
LL ans = input[j];
for(LL i=0;i<=300000000;i++){
if(func3(func2(i))==1)
if(_func1(i) == ans){
printf("%lld",i);
break;
}
/* if(i % 100000 == 0)
printf("%d finished\n",i);*/
}
printf("-");
}
/************
x6 = 1229
**********/
LL cnt=1;
for(LL i=3;i<=10000;i++)
if(func4(i)==1)
cnt++;
printf("%lld}",cnt);
//flag{927369-19324816-44435556-3996001-9865881-1229}
}
Comments | NOTHING