February 13, 2022

MRCTF2020-Shit

0x00 日常查壳

无壳32位

image-20220213195601544

0x01 花指令

简单看了下main函数,会发现两个关键函数都有花指令,现在写个取花的脚本

image-20220213203524574

都是诸如此类的花,观测一下ida分析发现解析的还不一样,但都有的特征是call后面有add和retn的都是算花的,于是由此写了个去花的脚本(我仍未找到地址解析机器码的idc函数)

1
2
3
4
5
6
7
8
9
10
.text:0040147E                 call    loc_401486
.text:0040147E ; ---------------------------------------------------------------------------
.text:00401483 db 0E8h
.text:00401484 ; ---------------------------------------------------------------------------
.text:00401484 jmp short loc_40148B
.text:00401486 ; ---------------------------------------------------------------------------
.text:00401486
.text:00401486 loc_401486: ; CODE XREF: sub_401460+1E↑j
.text:00401486 add [esp+3Ch+var_3C], 1
.text:0040148A retn

运行在ida7.5版本上,就是把这段全部nop掉就没事了,设置一下起始和结束地址即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
st = 0x00401460
end = 0x00401630


def patchNop(start, end):
for i in range(start, end):
ida_bytes.patch_byte(i, 0x90)


def nextInstr(addr):
return addr + idc.get_item_size(addr)


addr = st
while ( addr < end ):
next = nextInstr(addr)
c = nextInstr(next)
jnext = c + 1
anext = nextInstr(jnext)
rnext = nextInstr(anext)
if idc.print_insn_mnem(next) == "call" and idc.print_insn_mnem(anext) == "add" and idc.print_insn_mnem(rnext) == "retn":
addr = nextInstr(rnext)
patchNop(next, next + idc.get_item_size(next))
patchNop(c, c + 1)
patchNop(jnext, jnext + idc.get_item_size(jnext))
patchNop(anext, anext + idc.get_item_size(anext))
patchNop(rnext, rnext + idc.get_item_size(rnext))
print("Patch %x" %next)
else:
addr = next

于是通杀了这片花,先u再c再p即可(各种api都找到了!!就是找不到地址解析机器码的)

image-20220213212709915

但后面的花又长的不一样了!!因为在buu上做,所以看到源码我也意识到不太对劲,好像多去掉了些是,于是究极懒人版2.0!

(用完后注意要把整个函数段全部按u成全部未定义,再c再p,就可以完全复原,要不然ida会部分解析成其他函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
st = 0x00401460
end = 0x00401630


def patchNop(start, end):
for i in range(start, end):
ida_bytes.patch_byte(i, 0x90)


def nextInstr(addr):
return addr + idc.get_item_size(addr)


addr = st
while ( addr < end ):
next = nextInstr(addr)
addnext = idc.get_operand_value(next, 0)
# print(hex(addnext))
if idc.print_insn_mnem(next) == "call" and idc.print_insn_mnem(addnext) == "add":
retnext = nextInstr(addnext)
addr = nextInstr(retnext)
patchNop(next, addr)
print("Patch: %X" %next)
else:
addr = next

4012F0的函数就完全复原了,把这个用在401460上会发现也完全复原了

image-20220213220243780

然后分析一下401460函数是个初始化值的函数,和我们的输入并没有什么关系,关键还是4012F0函数

0x02 反调试

于是只要动调即可,但这题是有反调试的,通过找对main的引用下断点调试,发现每次断到这

image-20220213223325022

直接打开程序

image-20220213223348871

选择本地,下个断点,再附加程序,直接search找到shit即可

image-20220213223555917

按F9跑起来,再输入一个长度为24的字符串,跑到这按F7进去,

image-20220213223739055

在这通过修改标志位过去

image-20220213223855614

现在回忆一下我们需要的是什么数据

image-20220213224641194

然后一个F4到这check函数

image-20220213225327092

去翻下数据即可拿到这串key

image-20220213225440132

0x03 GetFlag!

分析一下加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
char __cdecl sub_4812F0(const char *a1)
{
int v1; // esi
int v3; // [esp+14h] [ebp-14h]
int i; // [esp+1Ch] [ebp-Ch]
int v5; // [esp+20h] [ebp-8h]

v3 = 0;
for ( i = 0; i < strlen(a1); i += 4 )
{
v1 = __ROR4__(a1[i + 3] | (a1[i + 2] << 8) | (a1[i + 1] << 16) | (a1[i] << 24), byte_485034[i / 4]);// 将数组4位大端序存放 再逻辑右移key位
v5 = ((v1 << 16) | (unsigned __int16)~HIWORD(v1)) ^ (1 << byte_485034[i / 4]);// 高16位取反 再与低16位互换 再异或左移key位的1
if ( i > 0 )
v5 ^= v3; // 异或前一位加密后的值
v3 = v5;
if ( v5 != dword_485018[i / 4] ) // 判断
return 0;
}
return 1;
}

EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <stdlib.h>

int key[7]={ 0x3, 0x10, 0xD, 0x4, 0x13, 0xB };
unsigned int ks[6]={0x8c2c133a,0xf74cb3f6,0xfedfa6f2,0xab293e3b,0x26cf8a2a,0x88a1f279};//{0x8c2cecc5,0xf74cb3f6,0xfedf590d,0xab293e3b,0x26cf75d5,0x88a1f279};

int main(void)
{
unsigned int k = 0, bk = 0;
int i, j;

for ( i = 5; i >= 0; i-- )
if ( i > 0 )
ks[i] ^= ks[i - 1];
for ( i = 0; i < 24; i += 4 )
{
k = ks[i / 4];

k = (1 << key[i / 4]) ^ k;
k = ((k >> 16)) | ((~(k << 16)) & 0xffff0000);

k = ((k << key[i / 4])) | (k >> (32 - key[i / 4]));
// printf("%X\n",k);
for ( j = 0; j < 4; j++ )
printf("%c", k >> (24 - j * 8) & 0xFF);
}


return 0;
}

GetFlag!

image-20220213230358446

DASCTF X SU
🍬
HFCTF2022
🍪

About this Post

This post is written by P.Z, licensed under CC BY-NC 4.0.