文章目录
- Reverse
- crackme
- EasyRe
- babyRe
- easy_z3
- FloweyRSA
- easy_flower_tea
- mfx_re
- z3_revenge
- WHERE
Reverse
crackme
、
加了UPX壳,可以看到EP Section处UPX标识被修改了
用WinHex修改
之后UPX脱壳
得到flag。
EasyRe
逆向一下,先逆序,再做一些字符的替换,最后异或0x11.
for ( i = v6 - 1; i >= 0; --i )
v4[v6 - i + 111] = v4[i + 112];
这一部分,实际上就是将数组 v4
中的元素从索引 i
到 v6 - 1
复制到数组 v4
中的索引 v6 - i + 111
到 v6 + 110
的位置
EXP:
enc = ']P_ISRF^PCY[I_YWERYC'
trans_table = str.maketrans('YC', 'BX')
result = enc.translate(trans_table)
re_result = result[::-1]
flag = ''.join([chr(ord(char) ^ 0x11) for char in re_result])
print(flag)
# ISCTFSNXJSIAOWCBXNAL
babyRe
py逆向。用pyinstxtractor解包。
之后找到babyRe.pyc和struct.pyc 拖进WinHex中比较magic number
相同,没有魔改。则直接对babyRe进行反编译,使用uncompyle6 或者 pyc在线反编译
发现是个rsa加密,结合output;已知(p+1)*(q+1)和(p+q);那么根据简单的数学公式,我们可以知道phi 即 (p-1)(q-1) = (p+1)(q+1) - 2(p+q),以及n = p * q = (p+1)(q+1) - (p+q) - 1;
之后根据RSA的计算公式可以解出flag
EXP:
from Crypto.Util.number import long_to_bytes
from gmpy2 import invert
paddq=292884018782106151080211087047278002613718113661882871562870811030932129300110050822187903340426820507419488984883216665816506575312384940488196435920320779296487709207011656728480651848786849994095965852212548311864730225380390740637527033103610408592664948012814290769567441038868614508362013860087396409860
p1xq1=21292789073160227295768319780997976991300923684414991432030077313041762314144710093780468352616448047534339208324518089727210764843655182515955359309813600286949887218916518346391288151954579692912105787780604137276300957046899460796651855983154616583709095921532639371311099659697834887064510351319531902433355833604752638757132129136704458119767279776712516825379722837005380965686817229771252693736534397063201880826010273930761767650438638395019411119979149337260776965247144705915951674697425506236801595477159432369862377378306461809669885764689526096087635635247658396780671976617716801660025870405374520076160
c=5203005542361323780340103662023144468501161788183930759975924790394097999367062944602228590598053194005601497154183700604614648980958953643596732510635460233363517206803267054976506058495592964781868943617992245808463957957161100800155936109928340808755112091651619258385206684038063600864669934451439637410568700470057362554045334836098013308228518175901113235436257998397401389511926288739759268080251377782356779624616546966237213737535252748926042086203600860251557074440685879354169866206490962331203234019516485700964227924668452181975961352914304357731769081382406940750260817547299552705287482926593175925396
n = p1xq1 - paddq - 1
phi = p1xq1 - 2*paddq
e = 65537
d = invert(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
# ISCTF{kisl-iopa-qdnc-tbfs-ualv}
easy_z3
py文件打开,发现就是一堆约束条件,用python的z3约束求解。
根据源代码,还需要将计算出的整数转换为ascii码的形式。
EXP:
from z3 import *
s = Solver()
l = [Int(f"l_{i}") for i in range(6)]
s.add((593*l[5] + 997*l[0] + 811*l[1] + 258*l[2] + 829*l[3] + 532*l[4]) == 0x54eb02012bed42c08)
s.add((605*l[4] + 686*l[5] + 328*l[0] + 602*l[1] + 695*l[2] + 576*l[3]) == 0x4f039a9f601affc3a)
s.add((373*l[3] + 512*l[4] + 449*l[5] + 756*l[0] + 448*l[1] + 580*l[2]) == 0x442b62c4ad653e7d9)
s.add((560*l[2] + 635*l[3] + 422*l[4] + 971*l[5] + 855*l[0] + 597*l[1]) == 0x588aabb6a4cb26838)
s.add((717*l[1] + 507*l[2] + 388*l[3] + 925*l[4] + 324*l[5] + 524*l[0]) == 0x48f8e42ac70c9af91)
s.add((312*l[0] + 368*l[1] + 884*l[2] + 518*l[3] + 495*l[4] + 414*l[5]) == 0x4656c19578a6b1170)
flag = ''
if s.check() == sat:
model = s.model()
for i in range(6):
hex_model = hex(model[l[i]].as_long())[2:]
flag += "".join(chr(int(hex_model[j:j+2],16))for j in range(0,len(hex_model),2))
print(flag)
# ISCTF{N0_One_kn0ws_m@th_B3tter_Th@n_me!!!}
FloweyRSA
ida打开之后全是爆红,找到花指令的地方。
jz到label1中间的内容是混淆的东西,全部nop掉,
之后在main函数处用P 创建函数,根据提示对相应地址的内容进行修复(nop掉再C转化代码)修完之后,回到main处 P 一下,之后反编译就可以了。
得到:
可以知道是一个RSA加密,密文数据在c中,e为 465,n很小,可以分解得到 p 和 q。
EXP:
from Crypto.Util.number import long_to_bytes
from gmpy2 import invert
enc = [0x753C2EC5, 0x8D90C736, 0x81282CB0, 0x7EECC470, 0x944E15D3, 0x2C7AC726, 0x717E8070, 0x30CBE439, 0x0B1D95A9C,
0x6DB667BB, 0x1240463C, 0x77CBFE64, 0x11D8BE59]
e = 0x1D1
p = 56099
q = 56369
n = p * q
phi = (p - 1) * (q - 1)
d = invert(e, phi)
flag = b''
for key in enc:
m = pow(key, d, n)
flag += long_to_bytes(m)
print(flag)
# b'flag{reverse_is_N0T_@lways_jusT_RE_myy_H@bIb1!!!!!!}'
easy_flower_tea
IDA打开后无法加载,地址爆红,看汇编
直接NOP掉,然后P了反编译就好。
要求我们输入number 1 和number 2,对着俩个数进行加密之后进行验证。查看一下加密函数sub_41100A
就是一个简单的TEA加密。
EXP:
#include <stdio.h>
#include <stdint.h> // 使用uint32_t数据类型需要包含此头文件
#include <string.h>
#include<iostream>
using namespace std;
// 定义加密函数
// 定义加密函数
void tea_decrypt(uint32_t *v, uint32_t *k) {
uint32_t v0 = v[0], v1 = v[1], i; // 根据TEA算法,解密轮次的计算需要初始化sum
uint32_t delta = 0x61C88647;
uint32_t sum = -(delta*32);
for (i = 0; i < 32; i++) {
v1 -= ((v0 * 16) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
v0 -= ((v1 * 16) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
sum += delta;
}
v[0] = v0;
v[1] = v1;
}
int main() {
uint32_t enc[2]={1115126522,2014982346};
uint32_t key[]={12,34,56,78};
tea_decrypt(enc,key);
cout<<enc[0]<<endl;
cout<<enc[1];
return 0;
}
mfx_re
UPX魔改壳,使用WinHex将MFX都改成UPX,mfx改成upx就好了。之后用UPX脱壳
只有处–s[i],逆向一下就是 +1
EXP:
enc = 'HRBSEz51e1a81c,78b3,34d`,84`4,6acce2c776a0|'
print("".join(chr(ord(enc[i])+1)for i in range(len(enc))))
# ISCTF{62f2b92d-89c4-45ea-95a5-7bddf3d887b1}
z3_revenge
一样的用python的z3约束求解。
实际上v4可以看做v0,之后SBYTE1(v4)就是v1,SBYTE2(v4) 为v2;以此类推
z3可以解出
solution_values = [
73, 83, 67, 84, 70, 123, 53, 53, 54, 52, 48, 48, 53, 102, 45, 50, 100, 100,
56, 45, 52, 100, 57, 53, 45, 57, 100, 50, 55, 45, 48, 100, 98, 102, 52, 48,
48, 49, 57, 54, 49, 57, 125
]
flag = []
for i in range(len(solution_values)):
flag.append(chr(solution_values[i]))
print(''.join(flag))
# ISCTF{5564005f-2dd8-4d95-9d27-0dbf40019619}
WHERE
IDA打开
程序开始23行处设置了一个异常处理函数
- 使用了
NtCurrentTeb()
函数来获取当前线程的TEB - 访问
NtTib
结构,从中获取ExceptionList
成员的值。 - 在Windows中,
ExceptionList
是 TEB 的一部分,用于指向当前线程的异常链表的头部。 - 异常链表用于管理当前线程的异常处理信息,当线程执行发生异常时,系统会根据这个链表找到对应的异常处理程序。
之后往下看,
用 GetModuleHandleA
函数 获取 kernel32.dll 动态链接库中的 AddVectoredExceptionHandler
函数的地址,而AddVectoredExceptionHandler
函数用于向进程中添加一个矢量化的异常处理程序。所以这里也是关于异常处理的操作。
接着,
又一次通过 NtCurrentTeb()
函数来获取当前线程的TEB,这一次是通过访问TEB的 ProcessEnvironmentBlock
成员,最终获取了一个叫做 BeingDebugged
的成员的值。在Windows中, BeingDebugged
是用于指示当前进程是否被调试的,如果当前值为非零,表示进程正在被调试。
接上面,如果进程没有被调试,则这里会进入401520中,
这里看一下,似乎都是对调试器的操作,阻止动态分析。
还有一处loc_401660,点进去看看
发现一小段花指令,去除后发现是一个TEA加密,但是目前不清楚是哪里的。
再次返回主函数的时候,发现不见了。不知道是什么情况了,看了wp好像是 VEH异常处理还是SEH异常处理,不太懂(待学)
往下看。
第一部分flag的地方,可以用z3解出来。
再往下,
先验证了 Str 长度为32,爆红的不知道什么,好像是什么空指针异常,想起上面讲的异常处理函数,
点进去看,
发现是一个魔改了一点的RC4
接着看到 sub_401660,这里不就是1我们刚刚 修复的花指令处,虽然不懂具体的过程,但是这里应该就是 TEA加密。
再看下面。
这里拿 刚刚 TEA加密后的密文,先是异或,将得到的数据作为一个二维数组的索引,把当前位置的值设置为1,最后比较返回0。
其实到这里就分析完了。好像也不是很难,但是当初纠结了好久。
逆向一下就好了。
但是其实现在也还有点疑惑,为什么TEA加密的时候的明文和key是相同的,解密的时候密文和key也可以相同,当时就是这里纠结不出来。o(╥﹏╥)o、
具体的EXP就不再写了,分析完了。主要是这个拖了好久了,今天补一下。可以去找官方wp。有EXP。