BaseCTF一些简单的逆向题(持续更新中~)
Reverse
在逆向方面我也是个十足的萌新,记录一下萌新的学习过程与思考
Ez_maze
一道简单的迷宫题

首先shift+f12看一下字符串,可以找到迷宫
同时也发现了flag的格式

然后进入到main函数看一下,因为我们需要知道迷宫的格式


可以看出v5其实就是我们输入的wsad,v3是其ascii码值,因此可以判断出迷宫是15*15
然后我们便知道了迷宫的图,只需要手动绘制出最短路径即可

转换成md5值后提交成功!
ez_xor
拿到题目后将exe放入ida

用cmd尝试运行一下,先叫我们输入一个值,然后进行判断
看代码,判断的地方就是checkflag
是将我们输入的值和v15进行每一位的判断,判断是否相同
因此flag就是v15的值
往上看,有个encrypt加密,这是对我们输入的值进行异或加密

V10是我们输入的值
其实这里就是v10[i]^=v20[27-i] 对我们输入的值进行异或加密,密钥是v20
那么v20又是从哪来的呢?我们再往上看,有个keystream

这里其实是v20[i]=i^v9[i%3] 为v20(密钥)赋值v9又是什么呢?上面给到了

大部分情况下你能见到的计算机使用的都是“小端序”,对于一个字节放不下的整数,会按顺序存放最低字节、次低字节、……
但编程时写的(IDA伪代码看到的)是我们实际使用的数据。
因此这里是低字节放高位置 Xor
最后我们就可以编写代码了
temp=[]
v9='Xor'
for i in range(28):
temp.append(i^ord(v9[i%3]))
print(temp)
v15='1D0B2D2625050901'
v16='673D491E20317A24'
v17='34056E2E2508504D'
v18='253B4022'
v15=bytes.fromhex(v15)[::-1]
v16=bytes.fromhex(v16)[::-1]
v17=bytes.fromhex(v17)[::-1]
v18=bytes.fromhex(v18)[::-1]
Str=v15+v16+v17+v18
print(Str)
flag=''
for i in range(28):
flag+=chr(Str[i]^temp[27-i])
print(flag)
ez_base
首先根据字符串定位主函数

读代码,发现这行灰色的是对原来的base表做一些操作,不出意外就是换表,动调一下看换表后的表

CDABGHEFKLIJOPMNSTQRWXUVabYZefcdijghmnklqropuvstyzwx23016745+/89
再看v6 = sub_14001115E((__int64)v7, (__int64)v5, v8, (__int64)v9);
是对输入的v7进行加密,就是base编码,但是发现这里存在v9,那就可能是魔改的base编码
先看看下面的if函数if ( (unsigned int)sub_140011069(v6) )
其实就是对输入的判断,判断是否一致

这里就是判断v6与其中的那一串是否一致,那么那一串解码后就是flag
接下来我们去看魔改的base编码

其他都没什么区别,就是编码索引值加了,所以我们减回去就行。
接下来给出python代码:
table='CDABGHEFKLIJOPMNSTQRWXUVabYZefcdijghmnklqropuvstyzwx23016745+/89'
flag='TqK1YUSaQryEMHaLMnWhYU+Fe0WPenqhRXahfkV6WE2fa3iRW197Za62eEaD'
key=[1,2,3,4]
index=[]
for i in range(len(flag)):
tmp=table.index(flag[i])-key[i%4]
if tmp>=0:
index.append(tmp)
else:
index.append(tmp+64)
print(index)
for i in range(0,len(index),4):
a=index[i]
b=index[i+1]
c=index[i+2]
d=index[i+3]
sum=a<<18|b<<12|c<<6|d
for j in range(3):
print(chr((sum>>((2-j)*8))&0xff),end='')

Ezpy
首先用pydumpck对其进行反编译
在反编译成功的文件夹中找到如下代码与密钥





可以知道这是RC4加密算法,由于Rc4这种加密既是加密也是解密所以我们只需要对源码进行修改复原在把密文传进去就会有flag

tea
刚开始找不到main函数,那就shift+f12一下通过字符串来定位主函数main

最后比较v6和v7,true则正确,v7是我们输入的字符串
那么v6就是flag
然后我们在比较的上方发现了一个for循环,这应该是对v7的加密
跟进一下

Tea加密没跑了,delta是0x114514,key是v5,写一个tea解密就行,同时不要忘了前面的for循环。脚本如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define DELTA 0x114514
void decrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1], sum = DELTA*32, i; /* set up */
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3]; /* cache key */
for (i = 0; i < 32; i++) { /* basic cycle start */
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
sum -= DELTA;
} /* end cycle */
v[0] = v0; v[1] = v1;
}
int main() {
uint32_t v[10] = { 0x94B1F1E7 ,0x21D5D352 ,0x5247793D ,0x40D1C97 ,0xF36E7F74 ,0x9C53F70F ,0x6AEACFD8 ,0x6F9F06F4 ,0xEAFD9E2E ,0x32B655F7 };
uint32_t k[4] = { 0x11223344 ,0x55667788 ,0x99AABBCC ,0xDDEEFF11 };
for (int i = 0; i < 5; i++) {
decrypt(&v[i * 2], k);
}
puts((char*)v);
}

UPX

有壳,用upx脱壳一下,但是发现脱壳失败
去010editor看一下

原本大写的标志位改成小写的了,所以导致我们不能正常脱壳
改回大写,再脱壳,脱壳成功

其实就是把输入的字符串进行b64函数处理后与target进行比较
那么target其实就是b64处理后的flag $rg7_dhd~Alidg+zeyhz`vnz_d,7sy0=
接下来看一下b64函数
这其实就是一个base64编码,但是target长得很奇怪,肯定是换表了的。
这里可以shift+f12看表


baseplus

将str1的值与后面的值进行比较,一样即可。
而str1的值是v5进行encode后的值



函数实现了一个Base64编码,然后对编码后的结果进行了0e的异或
因此我们只需要将flag的值进行0e的异或后再根据base表解码即可

neuro爱数学
先尝试运行一下exe文件,发现要输入九个值

再往下看

For循环中进行了阶乘操作
i^0coeffs[0]+ i^1coeffs[1]+ i^2coeffs[2]+…+. i^8coeffs[8]
进行完阶乘操作后进行if判断
if ( i == 44
|| i == 58
|| (::v12 = i + 37, (unsigned int)(i + 37) <= 0x36)
&& (v14 = &::v5, v13 = (unsigned int)::v12, v6 = ::v5, (v12 = _bittest64(&v6, (unsigned int)::v12)) != 0) )
进入这个if操作result要等于0才能绕过
Else if result要不等于0才行
看这个i == 44
|| i == 58
可以先对这个if进行本地运算
#include <stdio.h>
#include <stdlib.h>
#include <cstdint>
#include <intrin.h>
int main() {
//初始化v5变量
uint64_t v5 = 0x400C0210000001LL;
for (int i = -60; i <= 59; i++) {
if (i == 44 || i == 58) {
printf("符合条件:%d\n", i);
continue;
}
int v12 = i + 37;
if (v12 <= 54 && _bittest64((const int64_t*)&v5, v12)){
printf("符合条件:%d\n", i);
}
}
return 0;
}

其实就是(x + 37) * (x + 9) * (x + 4) * (x - 5) * (x - 6) * (x - 17) * (x - 44) * (x - 58)
其实看到i^0*coeffs[0]+ i^1*coeffs[1]+ i^2*coeffs[2]+…+. i^8*coeffs[8]就应该想到上面这种式子
这种(x+a)*(x+b)*(x+c)*(x+d)展开后其实就是a*x^8 +b*x^7 +…+c*x^0这种形式的
再看上面的

我们可以发现coeffs这个数组其实就保存了我们输入的整数,其实就是多项式的系数
只要我们输入的系数满足这个多项式的两个条件
1.进入这个if操作result要等于0才能绕过
2.Else if result要不等于0才行
因此我们输入正确的系数才能获取flag,那么怎么获得(x + 37) * (x + 9) * (x + 4) * (x - 5) * (x - 6) * (x - 17) * (x - 44) * (x - 58)的系数呢?
这里就可以用python中的sympy库
from sympy import symbols, expand
# 定义变量
x = symbols('x')
# 构建多项式
polynomial = (x + 37) * (x + 9) * (x + 4) * (x - 5) * (x - 6) * (x - 17) * (x - 44) * (x - 58)
# 展开多项式
expanded_polynomial = expand(polynomial)
# 转换为标准形式
standard_form = expanded_polynomial.as_poly()
# 获取系数
coefficients = standard_form.all_coeffs()
# 输出系数(从高次到低次)
print("展开的多项式:", expanded_polynomial)
print("系数:", coefficients[::-1]) # 反转系数顺序,以从低次到高次显示


ezAndroid
放入jadx中进行反编译,在manifest中找到主函数后进入主函数进行代码审计

将我们输入的字符串进行所谓的base64编码后再与flag进行比较
这里我们先跟进所谓的base64编码函数

发现加载了hello的so库,那么我们将apk解压后将so文件放入ida进行反编译即可

可以发现其实并不是base64编码,而是进行了异或运算
异或key如下,在反编译代码中寻找即可

然后我们在asset中取出flag然后编写脚本即可
key='a6b4d4fe3461'
ascii_list=[ord(key[i]) for i in range(len(key))]
with open('flag','rb')as f:
flag=f.read()
for i in range(len(flag)):
print(chr(flag[i] ^ ascii_list[i%12]),end='')
Dont Debug Me
F5拿到伪代码。逻辑很清晰,就是一堆反调试,本题考的就是怎么绕过反调试,看看ex1t函数吧,这就是加密函数,顺着ex1t->o0Oh就可以看到

说明只要绕过反调试,那么程序就会自行输出flag。
那么先把断点设在第一个反调试的if语句那里,然后使用本地调试器,按TAB键转到流程图,然后开始F8步过,

到了这,0000000000401F7D这一行的jz语句下方的两个箭头,右边这个在闪动,意思是下一步程序会往箭头所指的方向运行,那就是结束程序了,那么我们可以选择修改标志位寄存器,ZF,来进行绕过,

双击ZF的值,就可以修改了,
修改完之后,可以看到原本闪动的箭头不变了,另一个在闪,后面还有两次(如果按照程序提示输入1的话,否则就是一次)绕过同理,在程序最后快结束的时候,查看终端窗口,可以看到flag了

浙公网安备 33010602011771号