标签:主函数 符号 静态 sctf block user ada item ***
三个check
第一个是直接比较:c92bb6a5
第二个是解密文件:a6c30091
第三个是解密数据:24566d882d4bc7ee
拼起来就是flag
迷宫题,uhjk控制方向
jkkjjhjjkjjkkkuukukkuuhhhuukkkk
md5加个密就是flag
输入假flag过前边的check
Nep{mircle_and_maho_is_not_free}
在sub_403000
有个SMC,会生成flag
v5 = sub_403000;
v4 = 0;
while ( (signed int)v5 < (signed int)&unk_403240 - 7 )
{
*(_BYTE *)v5 ^= aNepMircleAndMa[aNepMircleAndMa[0] % 32] & 0x10;
++v4;
v5 = (void (*)())((char *)v5 + 1);
}
对称加密,加密方法是每一位异或上一个固定的数
#include <cstdio>
char a[]="Nep{11111111111111111111111111111111}";
char b[]={128, 89, 35, 53, 43, 7,141,110, 38, 84, 51,232, 83, 85,132, 14,195,
146, 44,172,247, 27, 3,146, 35,125, 23,139, 40, 75, 31, 53,115,129,
158,154, 34};
char c[]={0x80,0x59,0x23,0x35,
0x22,0x73,0x8D,0x1A,
0x51,0x5D,0x30,0xE8,
0x57,0x26,0xF6,0x7,
0xC6,0x92,0x5E,0xDC,
0x83,0x1F,0x76,0x92,
0x25,0x0F,0x65,0xFB,
0x2E,0x4D,0x6B,0x45,
0x3,0x87,0xE9,0x9F,
0x22};
char s[38];
int main(){
for (int i=0;i<37;i++) s[i]=a[i]^b[i]^c[i];
printf("%s",s);
}
开头的opcode经过修改,导致不能正常运行
可以让0号指令直接跳到11号指令,再把中间的nop掉就可以了
用dis.disassemble
就可以直接看带符号的代码了
1 0 JUMP_ABSOLUTE 11
3 STOP_CODE
4 STOP_CODE
5 STOP_CODE
6 STOP_CODE
7 STOP_CODE
8 STOP_CODE
9 STOP_CODE
10 STOP_CODE
>> 11 LOAD_CONST 1 (None)
14 IMPORT_NAME 0 (base64)
17 STORE_NAME 0 (base64)
20 LOAD_CONST 2 (‘YamaNalaZaTacaxaZaDahajaYamaIa0aNaDaUa3aYajaUawaNaWaNajaMajaUawaNWI3M2NhMGM=‘)
23 STORE_NAME 1 (a)
26 LOAD_NAME 2 (raw_input)
29 LOAD_CONST 3 (‘Are u ready?‘)
32 CALL_FUNCTION 1
35 STORE_NAME 3 (flag)
38 LOAD_NAME 0 (base64)
41 LOAD_ATTR 4 (b64encode)
44 LOAD_NAME 3 (flag)
47 CALL_FUNCTION 1
50 STORE_NAME 5 (c)
53 LOAD_NAME 6 (list)
56 LOAD_NAME 5 (c)
59 CALL_FUNCTION 1
62 STORE_NAME 7 (d)
65 SETUP_LOOP 39 (to 107)
68 LOAD_NAME 8 (range)
71 LOAD_CONST 4 (0)
74 LOAD_CONST 5 (32)
77 CALL_FUNCTION 2
80 GET_ITER
81 FOR_ITER 22 (to 106)
84 STORE_NAME 9 (i)
87 LOAD_NAME 7 (d)
90 LOAD_NAME 9 (i)
93 DUP_TOPX 2
96 BINARY_SUBSCR
97 LOAD_CONST 6 (‘a‘)
100 INPLACE_ADD
101 ROT_THREE
102 STORE_SUBSCR
103 JUMP_ABSOLUTE 73
>> 106 POP_BLOCK
>> 107 LOAD_CONST 7 (‘‘)
110 LOAD_ATTR 10 (join)
113 LOAD_NAME 7 (d)
116 CALL_FUNCTION 1
119 STORE_NAME 11 (ohh)
122 LOAD_NAME 11 (ohh)
125 LOAD_NAME 1 (a)
128 COMPARE_OP 2 (==)
131 POP_JUMP_IF_FALSE 134
18 >> 134 LOAD_CONST 8 (‘great!waht u input is the flag u wanna get.‘)
137 PRINT_ITEM
138 PRINT_NEWLINE
139 JUMP_FORWARD 5 (to 147)
142 LOAD_CONST 9 (‘pity!‘)
145 PRINT_ITEM
146 PRINT_NEWLINE
>> 147 LOAD_CONST 1 (None)
150 RETURN_VALUE
翻译一下
import base64
a=‘YamaNalaZaTacaxaZaDahajaYamaIa0aNaDaUa3aYajaUawaNaWaNajaMajaUawaNWI3M2NhMGM=‘
flag=raw_input(‘Are u ready?‘)
c=base64.b64encode(flag)
d=list(c)
for i in range(0,32):
d[i]=d[i]+‘a‘
ohh=‘‘.join(d)
if a==ohh:
print ‘great!waht u input is the flag u wanna get.‘
else:
print ‘pity!‘
把a都删了再b64decode
就可以了
一进来会有一个除0的操作进SEH
转到sub_401250
,处理SMC
loc_40129C
也是个反调
再转到loc_401080
进入VM
执行asc_41D799
存放的类bf指令
不过这个函数体被裁剪过了,需要在结尾patch个ret才能F5
void __usercall sub_401080(int a1@<ebx>, int a2@<edi>)
{
unsigned int op; // eax
char pt; // dl
const char *v4; // esi
int v5; // eax
int v6; // ecx
op = ‘+‘;
pt = ptr;
v4 = "****--:~+******^.~+*****:*+++++^.-:///--*^.:///---^.,:~-----^>,:~-/++++++++++++^>,:~+****--^>+*******://+++++++++"
"+^:,^>-:///^:,^>+******://-^:,^>-/+://+++++++^:,^>-/----:,^>-/+:/+++++^:,^>-:++****+^:,^>-/+:~+**++^:,^>+****:*^:"
",^>-:++****++++^:,^>-/---:,^>+*****://+^:,^>-/+:///+^:,^>,";
while ( 2 )
{
switch ( op )
{
case ‘*‘:
mem[pt] *= 2;
goto LABEL_15;
case ‘+‘:
++mem[pt];
goto LABEL_15;
case ‘,‘:
scanf_0("%2x", &mem[pt]);
pt = ptr;
goto LABEL_15;
case ‘-‘:
--mem[pt];
goto LABEL_15;
case ‘.‘:
scanf("%c", (unsigned __int8)mem[pt]);
pt = ptr;
goto LABEL_15;
case ‘/‘:
mem[pt] = (unsigned __int8)mem[pt] >> 1;
goto LABEL_15;
case ‘:‘:
reg = mem[pt];
goto LABEL_15;
case ‘<‘:
ptr = --pt;
goto LABEL_15;
case ‘>‘:
ptr = ++pt;
goto LABEL_15;
case ‘^‘:
mem[pt] ^= reg;
goto LABEL_15;
case ‘~‘:
if ( (unsigned int)pt >= 50 )
goto LABEL_20;
mem[pt] = 0;
LABEL_15:
v5 = *v4++;
op = v5 - 42;
if ( op > 0x54 )
goto LABEL_16;
continue;
default:
LABEL_16:
v6 = 0;
break;
}
break;
}
while ( byte_41D8D0[v6] == mem[v6] )
{
if ( ++v6 >= 16 )
{
scanf("right\n");
sub_40374F(0);
LABEL_20:
sub_401413(a1, a2, (int)v4);
break;
}
}
scanf("wrong\n");
sub_40374F(0);
}
写个自动机
#include <cstdio>
char s[]="+****--:~+******^.~+*****:*+++++^.-:///--*^.:///---^.,:~-----^>,:~-/++++++++++++^>,:~+****--^>+*******://++++++++++^:,^>-:///^:,^>+******://-^:,^>-/+://+++++++^:,^>-/----:,^>-/+:/+++++^:,^>-:++****+^:,^>-/+:~+**++^:,^>+****:*^:,^>-:++****++++^:,^>-/---:,^>+*****://+^:,^>-/+:///+^:,^>,";
int ip=0;
int main(){
while(1){
if (s[ip]==‘*‘){
int t=1;
while(s[ip]==‘*‘) t*=2,ip++;
printf("mem[pt]*=%d\n",t);
}
if (s[ip]==‘/‘){
int t=1;
while(s[ip]==‘/‘) t*=2,ip++;
printf("mem[pt]/=%d\n",t);
}
if (s[ip]==‘+‘){
int t=0;
while(s[ip]==‘+‘) t++,ip++;
printf("mem[pt]+=%d\n",t);
}
if (s[ip]==‘-‘){
int t=0;
while(s[ip]==‘-‘) t++,ip++;
printf("mem[pt]-=%d\n",t);
}
if (s[ip]==‘<‘){
int t=0;
while(s[ip]==‘<‘) t++,ip++;
printf("pt-=%d\n",t);
}
if (s[ip]==‘>‘){
int t=0;
while(s[ip]==‘>‘) t++,ip++;
printf("pt+=%d\n",t);
}
if (s[ip]==‘:‘){
printf("reg=mem[pt]\n");
ip++;
}
if (s[ip]==‘^‘){
printf("mem[pt]^=reg\n");
ip++;
}
if (s[ip]==‘,‘){
printf("mem[pt]=getchar(\"%%2x\")\n");
ip++;
}
if (s[ip]==0) break;
if (s[ip]==‘.‘){
printf("mem[pt]=getchar(\"%%c\")\n");
ip++;
}
if (s[ip]==‘~‘){
printf("mem[pt]=0\n");
ip++;
}
}
}
parse一下
{
mem[pt]+=1
mem[pt]*=16
mem[pt]-=2
reg=mem[pt]
mem[pt]=0
mem[pt]+=1
mem[pt]*=64
mem[pt]^=reg
mem[pt]=getchar("%c") //N
mem[pt]=0
mem[pt]+=1
mem[pt]*=32
reg=mem[pt]
mem[pt]*=2
mem[pt]+=5
mem[pt]^=reg
mem[pt]=getchar("%c") //e
mem[pt]-=1
reg=mem[pt]
mem[pt]/=8
mem[pt]-=2
mem[pt]*=2
mem[pt]^=reg
mem[pt]=getchar("%c") //p
reg=mem[pt]
mem[pt]/=8
mem[pt]-=3
mem[pt]^=reg
mem[pt]=getchar("%c") //{
mem[pt]=getchar("%2x")
reg=mem[pt]
mem[pt]=0
mem[pt]-=5
mem[pt]^=reg
pt+=1
mem[pt]=getchar("%2x")
reg=mem[pt]
mem[pt]=0
mem[pt]-=1
mem[pt]/=2
mem[pt]+=12
mem[pt]^=reg
pt+=1
mem[pt]=getchar("%2x")
reg=mem[pt]
mem[pt]=0
mem[pt]+=1
mem[pt]*=16
mem[pt]-=2
mem[pt]^=reg
pt+=1
mem[pt]+=1
mem[pt]*=128
reg=mem[pt]
mem[pt]/=4
mem[pt]+=10
mem[pt]^=reg
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]-=1
reg=mem[pt]
mem[pt]/=8
mem[pt]^=reg
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]+=1
mem[pt]*=64
reg=mem[pt]
mem[pt]/=4
mem[pt]-=1
mem[pt]^=reg
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]-=1
mem[pt]/=2
mem[pt]+=1
reg=mem[pt]
mem[pt]/=4
mem[pt]+=7
mem[pt]^=reg
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]-=1
mem[pt]/=2
mem[pt]-=4
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]-=1
mem[pt]/=2
mem[pt]+=1
reg=mem[pt]
mem[pt]/=2
mem[pt]+=5
mem[pt]^=reg
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]-=1
reg=mem[pt]
mem[pt]+=2
mem[pt]*=16
mem[pt]+=1
mem[pt]^=reg
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]-=1
mem[pt]/=2
mem[pt]+=1
reg=mem[pt]
mem[pt]=0
mem[pt]+=1
mem[pt]*=4
mem[pt]+=2
mem[pt]^=reg
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]+=1
mem[pt]*=16
reg=mem[pt]
mem[pt]*=2
mem[pt]^=reg
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]-=1
reg=mem[pt]
mem[pt]+=2
mem[pt]*=16
mem[pt]+=4
mem[pt]^=reg
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]-=1
mem[pt]/=2
mem[pt]-=3
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]+=1
mem[pt]*=32
reg=mem[pt]
mem[pt]/=4
mem[pt]+=1
mem[pt]^=reg
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]-=1
mem[pt]/=2
mem[pt]+=1
reg=mem[pt]
mem[pt]/=8
mem[pt]+=1
mem[pt]^=reg
reg=mem[pt]
mem[pt]=getchar("%2x")
mem[pt]^=reg
pt+=1
mem[pt]=getchar("%2x")
}
if (mem[0:16]=={250, 43, 148, 234, 99, 168, 196, 19, 132, 231, 167, 218, 212, 45, 174, 190})
printf("right")
可以看出来是对称加密,每一位都异或一个固定的值
算法都有了就不搞反调了,直接把函数dump下就行了
Nep{fa2b94ea63a8c41384e7a7dad42daebe}
填进去解一下就有flag了
#include <cstdio>
typedef unsigned char byte;
byte ops[] = "+****--:~+******^.~+*****:*+++++^.-:///--*^.:///---^.,:~-----^>,:~-/++++++++++++^>,:~+****--^>+*******://+++++++++"
"+^:,^>-:///^:,^>+******://-^:,^>-/+://+++++++^:,^>-/----:,^>-/+:/+++++^:,^>-:++****+^:,^>-/+:~+**++^:,^>+****:*^:"
",^>-:++****++++^:,^>-/---:,^>+*****://+^:,^>-/+:///+^:,^>,";
byte reg;
int pt=0;
int ip=0;
byte mem[50];
int main()
{
while ( 2 )
{
byte op = ops[ip++];
if (!op) break;
switch ( op )
{
case ‘*‘:
mem[pt] *= 2;
break;
case ‘+‘:
++mem[pt];
break;
case ‘,‘:
scanf("%2x", &mem[pt]);
break;
case ‘-‘:
--mem[pt];
break;
case ‘.‘:
scanf("%c", &mem[pt]);
break;
case ‘/‘:
mem[pt] = mem[pt] >> 1;
break;
case ‘:‘:
reg = mem[pt];
break;
case ‘<‘:
--pt;
break;
case ‘>‘:
++pt;
break;
case ‘^‘:
mem[pt] ^= reg;
break;
case ‘~‘:
mem[pt] = 0;
break;
default:
break;
}
}
for (int i=0;i<16;i++)
printf("%02x",mem[i]);
}
动态debug编译,还不打包dll,出题人很可以的,就纯静态
主函数在sub_41A5B0
->sub_41121C
->sub_419A10
loc_41A68F
,loc_417A40
要nop掉混淆指令
TLS里有个PEB反调
int __userpurge TlsCallback_0_0@<eax>(int a1@<xmm0>, int a2, int a3, int a4)
{
int v4; // eax
v4 = *(_DWORD *)(*(_DWORD *)(__readfsdword(0x18u) + 48) + 104);
byte_3E7000 = v4;
return none(1, v4, a1);
}
byte_3E7000=PEB.NTGlobalFlag=0
sub_3D9350
也有个PEB反调
int __usercall sub_3D9350@<eax>(int a1@<xmm0>, int a2)
{
int v2; // eax
if ( (unsigned __int8)*(_DWORD *)(*(_DWORD *)(__readfsdword(0x18u) + 48) + 2) )
j_memset(byte_3E7004, 0, 0x14u);
v2 = sub_3D15E6(a1, a2);
LOBYTE(v2) = 0x30;
return none(1, v2, a1);
}
检测到PEB.BeingDebugged
会清除byte_3E7000
中的数据
把加密函数dump下来,直接按位爆破即可
#include "defs.h"
#include <cstring>
#include <cstdio>
typedef unsigned char byte;
int table0[256];
byte byte_3E7728[256];
int dword_3E7828[65536];
byte byte_427820[65536];
byte byte_3E7000=0;
byte unk_3E7004[65536];
byte backup[]={242, 168, 132, 235, 152, 159, 38, 251, 131, 148, 34,
220, 73, 3, 42, 234, 94, 21, 230, 96, 86, 158, 223,
217, 0, 0, 0, 0, 0, 0, 0, 0};
byte table[1024];
int bfunc(int a2)
{
int i; // [esp+D0h] [ebp-14h]
byte v4; // [esp+DFh] [ebp-5h]
v4 = 0;
for ( i = 0; *(_BYTE *)(i + a2); ++i )
{
*(_BYTE *)(i + a2) = ~((16 * *(_BYTE *)(i + a2) + v4) ^ ((signed int)*(unsigned __int8 *)(i + a2) >> 4) ^ 0x16);
v4 = *(_BYTE *)(i + a2);
}
}
int mktable0()
{
_BYTE *v1; // eax
int i; // [esp+D0h] [ebp-8h]
for ( i = 0; i < 256; ++i )
{
table0[i] = i;
v1 = (_BYTE *)(i + 1);
}
}
int mktable1(_DWORD *a2)
{
int v2; // eax
signed int i; // [esp+D0h] [ebp-20h]
*a2 = 98;
a2[1] = 97;
a2[2] = 100;
a2[3] = 95;
a2[4] = 119;
a2[5] = 111;
a2[6] = 109;
a2[7] = 97;
v2 = 32;
a2[8] = 110;
for ( i = 0; i < 256; ++i )
{
byte_3E7728[i] = a2[i % 9];
v2 = i + 1;
}
}
int mktable2()
{
_BYTE *v1; // eax
int v2; // STE8_4
signed int i; // [esp+D0h] [ebp-20h]
int v5; // [esp+DCh] [ebp-14h]
v5 = 0;
for ( i = 0; i < 256; ++i )
{
v5 = (byte_3E7728[i] + table0[i] + v5) % 256;
v2 = table0[i];
table0[i] = table0[v5];
table0[v5] = v2;
v1 = (_BYTE *)(i + 1);
}
}
int mktable3(int a2, int a3)
{
int v3; // eax
int v4; // ST0C_4
int v5; // STF8_4
int v7; // [esp+D4h] [ebp-44h]
int v8; // [esp+104h] [ebp-14h]
int i; // [esp+110h] [ebp-8h]
v7 = 0;
v8 = 0;
for ( i = 0; ; dword_3E7828[v7++] = table0[(table0[v8] + table0[i]) % 256] )
{
v3 = a3;
v4 = a3--;
if ( !v4 )
break;
i = (i + 1) % 256;
v8 = (table0[i] + v8) % 256;
v5 = table0[i];
table0[i] = table0[v8];
table0[v8] = v5;
}
}
int afunc(byte *input)
{
int v2; // edx
int v3; // ST04_4
int i; // [esp+250h] [ebp-42Ch]
int v7; // [esp+670h] [ebp-Ch]
int savedregs; // [esp+67Ch] [ebp+0h]
v7 = strlen((char *)input);
memset(&table, 0, 0x400u);
mktable0();
mktable1((_DWORD *)table);
mktable2();
mktable3((int)input, v7);
for ( i = 0; i < v7; ++i )
{
v2 = i;
byte_427820[i] = input[i] ^ LOBYTE(dword_3E7828[i]) ^ byte_3E7000;
}
}
int clear(){
memcpy(unk_3E7004,backup,sizeof(backup));
memset(table0,0,sizeof(table0));
memset(byte_3E7728,0,sizeof(byte_3E7728));
memset(dword_3E7828,0,sizeof(dword_3E7828));
memset(byte_427820,0,sizeof(byte_427820));
memset(table,0,sizeof(table));
}
int main(){
byte s[]="Nep{0000000000000000000}";
for (int i=0;i<24;i++){
for (int j=0;j<128;j++){
s[i]=j;
clear();
afunc(s);
bfunc((int)unk_3E7004);
if (byte_427820[i]==unk_3E7004[i]) break;
}
}
for (int i=0;i<24;i++) printf("%c",s[i]);
}
md5加密一下就是flag
DASCTF 2020 六月赛 Reverse Writeup
标签:主函数 符号 静态 sctf block user ada item ***
原文地址:https://www.cnblogs.com/algonote/p/13196699.html