Reverse

shell

这题是re的第二题,结果是签到题。。。

ida走一波。

file

似乎就N1函数有点用?跟进去康康。

file

似乎是jiake函数对we那块进行处理然后把we那块当函数调用?有简单混淆那味了。那就再跟进去康康。

file

调用是jiake(we, 738, 5),那实际上就是从we那块开始每字节异或5,走个738长。

至于we到底在哪,因为上面__main函数似乎定义了全局变量一样的东西,所以we就是ssd,而ssd函数的起始基址用010搜一下hex特征就找到了,就是0x900。(应该可以在ida里直接找,但是我菜,不会)

file

那就直接写脚本修一下we那块然后再重新用ida打开康康正确的代码是啥。

with open('shell_e55a9fa7062b9e0b4ba412ca3584b543.exe', 'rb') as f:
    data = bytearray(f.read())
for i in range(738):
    data[0x900+i] ^= 5
data = bytes(data)
with open('shell_true.exe', 'wb') as f:
    f.write(data)

再去看一下ssd函数,就是定义一个字符串v24和一个数组v4然后各种简单运算处理嘛,用python倒着走一波就完事。

file

target1 = [0x51,0xb8,0x5a,0x12,0x10,0xfa,0xd,0x23,1,0x17,8,9,0x1b,0,0x12,0x2c,0xf2,0x12,0x11,0xe]
target2 = bytearray("REVERSE".encode())

for i in range(7):
    target2[i] %= 64

for i in range(20):
    if target2[i % 7] & 1 != 0:
        target1[i] -= 2
    else:
        target1[i] -= 1

for i in range(10):
    tmp = target1[i]
    target1[i] = target1[20 - i - 1]
    target1[20 - i - 1] = tmp

for i in range(20):
    target1[i] -= target2[i % 7]

print(target1)

for i in range(18, -1, -1):
    target1[i] += target1[i+1]
    target1[i] %= 256

for i in range(20):
    target1[i] += 64
    target1[i] %= 256

print(bytes(target1))

file

flag{celebrate_you!}

getmiao

刚开始比赛一看这题是re1,直接就上手了,也没看多少分。(我是憨批)

ida看了下函数挺乱的,就先动态调一波跟一波调用康康哪里是核心函数。

然后就跟到了4257b0这块。

file

这题用ida 7.0应该是没法看伪代码的,幸好我赛前升级成了ida 7.6,现在打算之后多版本共存以防万一了。

file

看代码的话,输入16位的key,然后用4112c6处理一下输出到v15,再把v15411217处理一下输出到v13,然后v13应该就要和上面那个预置的v16数组一致才行。

那就跟进去康康这俩函数。

4112c6的话,最终数据落地应该是a4指针,但是这边有个this就很奇怪,感觉是ida没正确解析?

file

不过问题不大,应该就是生成a5然后按字节和key异或就是a4

至于a5的话,我选择动态调试直接拿数据,毕竟已经发现这时候的ida有点不靠谱了。

ida给出的异或操作地址是41d9b9,那么就在这下个断点康康数据。

输入0123456789abcdef用来测试。回车后成功在断点处暂停。

file

可以发现eax是key,那么ecx就是上面那个生成的a5数组。所以往上面找找ecx的赋值处,然后下个断点重新执行康康其内存数据是个啥。

file

重新执行到达这个断点后,转到内存数据发现只有一个孤零零的0x63,那么数据确实是每轮实时生成的,那就直接跳个16轮康康最终结果。

file

所以最终得到的a5就是0x63, 0x87, 0x07, 0x03, 0x70, 0x51, 0x12, 0xC4, 0xDB, 0xBB, 0x8C, 0xAA, 0xC3, 0xB5, 0x8B, 0xBB

那么这个4112c6函数基本上就看完了,再去看下411217的过程。

file

这个看起来似乎可以不用管中间的一大段,只要把v11和输入的a2也就是上面传入的v15异或就能得到最终结果。

那么就可以写脚本去生成key了。

a = [0x31, 0xD0, 0x0C, 0x05, 0x24, 0x11, 0x42, 0xCA, 0xCC, 0xBA, 0xD8, 0xE5, 0xC9, 0xEA, 0x8E, 0xBE]
x = "49ba59abbe56e057".encode()
xx = [0x63, 0x87, 0x07, 0x03, 0x70, 0x51, 0x12, 0xC4, 0xDB, 0xBB, 0x8C, 0xAA, 0xC3, 0xB5, 0x8B, 0xBB]
key = []
for i in range(16):
    key.append(((a[i]) ^ x[i]) ^ xx[i])
print(bytes(key).decode())

得到keyfnigay1ludayoo02

然后去输入,没有任何反应直接等个几秒就崩了,题目说这个是正常情况,多试几次就能成,于是我信了他的邪,试了几十次没有一次成功的。。。找赛务反馈说可能是我环境的问题,然后用队友的机子确实能多试几次出下一步,但是队友那也没做re的环境啊。。。期间另一个队还把这题拿一血了,好气。

于是没办法,想接着动态调试做题是没辙了,只能硬着头皮静态分析去了。

file

看下面的步骤应该是把一个0x11400的块分成4416*16的矩阵,然后一行一行和key异或过去。但是矩阵的原始本体ida又给认错了,肯定不是Str啊,于是猜测这时候应该是还没崩的,打算去接着跟调试看看具体异或了个啥玩意。

这次xor在ida给出的基址是4259c9,于是去下个断点然后输入正确的key看看参与计算的是啥。

file

发现ecx是输入的key,那么就肯定是edx才是那个要找的数据了,所以往上找到edx的赋值,然后重新执行康康内存是哪块的,如果是直接从静态数据读取的那就很舒服。

file

把这个数据在010里搜一下,还真是静态直接读入的,地址是0x21c90,那就用python直接读取然后处理一下就完事。

file

with open('getmiao.exe', 'rb') as f:
    data = f.read()[0x21c90:0x21c90+0x11400]
data = bytearray(data)
for i in range(0x11400 // 16):
    for j in range(16):
        data[16*i+j]^=key[j]
with open('data', 'wb') as f:
    f.write(bytes(data))

然后根据ida那边后面的处理过程,应该是把这个当成dll载入然后调用哪个函数的(也可能猜错了,反正就是套娃执行),那感觉应该和getmiao这个程序没关系了,直接看提取出来的dll吧。

ida打开一看,大大的main_0函数摆着,挺好。主要就是输入的flag用411578处理下,然后跟内置的v6数组比较(4111D6跟进去看了下就是个简单比较,不过比较的有19字节,所以实际上v7也会跟在v6后面当作v6的数据去越界读取)。

file

file

所以就去看看411578的过程呗。

file

主要就是和内置的v6数组按字节异或,其他应该没啥,所以还是写个脚本去生成flag呗。

target = [0x85, 0x4d, 0x4c, 0xdb, 0x9, 0x2f, 0xe9, 0xb3, 0xdc, 0xf5, 0xe3, 0x3f,0x6c, 0xe, b'D'[0], b'X'[0], b'Z'[0], b'm'[0], b')'[0]]
x = [0xed, 0x28,0x35, 0x84, 0x30, 0x4a, 0x9d,0xec, 0xba,0xc4,0x91,0xa,0x18,0x51,0x22, 0x69,0x3b,0xa,0x8]
for i in range(19):
    print(chr(x[i]^target[i]), end='')

成功拿下二血。

flag{hey_9et_f1r5t_f1ag!}


The End