入门逆向
嗯。
Easy_vb
嗯。
Easy_re
嗯。
游戏过关
flag通过硬编码生成,爆破关键跳即可
Timer
安卓逆向,看样子和上题类似,直接爆破判断点即可,不过要算出一个关键值
根据程序逻辑可以直接算出最终的f320k的值,代码如下
public static void main(String[] args) {
int beg = (((int) (System.currentTimeMillis() / 1000)) + 200000);
long f321t = System.currentTimeMillis();
int now = (int) (f321t / 1000);
int size = beg - now;
int f320k = 0;
for (int i = size; i > 0; i--) {
if (is2(i)) {
f320k += 100;
}
else {
f320k--;
}
}
System.out.println(f320k);
}
public static boolean is2(int n) {
if (n <= 3) {
if (n > 1) {
return true;
}
return false;
} else if (n % 2 == 0 || n % 3 == 0) {
return false;
} else {
int i = 5;
while (i * i <= n) {
if (n % i == 0 || n % (i + 2) == 0) {
return false;
}
i += 6;
}
return true;
}
}
}
然后修改下smali文件并保存
重新编译运行
逆向入门
运行不了,file一下发现是可打印字符,strings一下发现是个图片的base64
随手写个脚本解一下
import base64
f = open('admin.exe', 'r')
data = f.read()
f.close()
img = data[data.find(',')+1:]
img = base64.b64decode(img)
f = open('admin.png', 'wb')
f.write(img)
f.close()
嗯。
love
import base64
data = 'e3nifIH9b_C@n@dH'
data = [ord(c) for c in data]
for i in range(len(data)):
data[i] -= i
data = base64.b64decode(''.join([chr(c) for c in data]))
print data
嗯。
LoopAndLoop
一眼就能看到关键的比较位置
而chec是native层函数
估计是递归调用check1,check2,check3,因为这3个函数又会调用chec,具体调用哪一个由arg4来决定。仔细看一下这三个函数的代码,发现这里用的是尾递归,而尾递归的运算模式本质上是迭代,且这里的运算是可逆的,可写解密程序
public static void main(String[] args) {
int num = 1835996258;
for (int i = 99; i > 1; i--) {
int c = i * 2 % 3;
switch(c) {
case 0:
for (int j = 0; j < 100; j++) {
num -= j;
}
break;
case 1:
if ((i-1) % 2 == 0) {
for (int j = 1; j < 1000; j++) {
num -= j;
}
}
else {
for (int j = 1; j < 1000; j++) {
num += j;
}
}
break;
case 2:
for (int j = 1; j < 10000; j++) {
num -= j;
}
break;
}
}
System.out.println(num);
}
这是什么鬼格式。。。,输入求得的值
easy-100
本来这个题流程很简单,硬是被搞成了一个函数在多个类中胡乱调用,且各个类的一些函数名还是相同的,要慢慢得看完才行。总之这就是一个AES加密然后与密文比较的过程。解密脚本如下:
from Crypto.Cipher import AES
data = [0x15, 0xa3, 0xbc, 0xa2, 0x56, 0x75, 0xed, 0xbc,
0xa4, 0x21, 0x32, 0x76, 0x10, 0x0d, 0x01, 0xf1,
0xf3, 0x03, 0x04, 0x67, 0xee, 0x51, 0x1e, 0x44,
0x36, 0xa3, 0x2c, 0xe9, 0x5d, 0x62, 0x05, 0x3b]
with open('url.png', 'rb') as f:
content = f.read()[144:144+16]
key = ''
for i in range(0, len(content), 2):
key += content[i + 1]
key += content[i]
data = ''.join([chr(c) for c in data])
def decrypt(data, key):
aes = AES.new(key, AES.MODE_ECB)
text = aes.decrypt(data)
return text
print decrypt(data, key)
SafeBox
很容易的一题,但真正的验证过程不在MainActivity过程中,而在androidTest,验证流程很简单,可以直接爆破,不过脑袋抽了用了z3,贴代码
from z3 import *
x = Int('x')
s = Solver()
s.add(x > 10000000)
s.add(x < 99999999)
t = 1; t1 = 10000000
s.add((x % 1000) % 584 == 0)
s.add(((x / 1000) % 100) - 36 == 3)
for i in range(3):
s.add((x / t) % 10 == (x / t1) % 10)
t *= 10
t1 /= 10
print s.check()
m = s.model()
x = int('%s' % m[x])
c1 = x / 1000000
c2 = ((x / 10000) % 100)
c3 = (((x / 100) % 100) + 10)
flag = 'NJCTF{have' + chr(c1) + chr(c2) + chr(c3) + 'f4n}'
print flag
Mountain climbing
本题的逆向分析其实很容易,主要考察关于算法的编程问题。主函数逻辑比较清晰,代码如下:
__int64 main_0()
{
int v0; // ecx
int random; // eax
int v2; // ecx
int v3; // ecx
int v4; // edx
int v5; // ecx
int v6; // ecx
__int64 v7; // ST04_8
int index; // [esp+D0h] [ebp-90h]
int j; // [esp+DCh] [ebp-84h]
int i; // [esp+E8h] [ebp-78h]
char input[104]; // [esp+F4h] [ebp-6Ch]
srand(12u);
j_memset(&unk_423D80, 0, 0x9C40u);
for ( i = 1; i <= 20; ++i )
{
for ( j = 1; j <= i; ++j )
{
random = rand();
v0 = j;
table[100 * i + j] = random % 100000;
}
}
printf(v0, "input your key with your operation can get the maximum:");
scanf(v2, "%s", input);
if ( j_strlen(input) == 19 )
{
sub_41114F();
index = 0;
j = 1;
i = 1;
v5 = 1;
sum += table[101];
while ( index < 19 )
{
if ( input[index] == 'L' )
{
v5 = 400 * ++i;
sum += table[100 * i + j];
}
else
{
v6 = input[index];
if ( v6 != 'R' )
{
printf(v6, "error\n");
system("pause");
goto LABEL_18;
}
v5 = table[100 * ++i + ++j] + sum;
sum += table[100 * i + j];
}
++index;
}
printf(v5, "your operation can get %d points\n", sum);
system("pause");
}
else
{
printf(v3, "error\n");
system("pause");
}
LABEL_18:
HIDWORD(v7) = v4;
LODWORD(v7) = 0;
return v7;
}
大概就是设置了个随机数种子,然后生成一个三角形,每次可以选择向右或向左走,要求在结尾处走过的路径的值的和最大,也就是个深度优先遍历的问题。且其中一个函数对一段代码段进行了解密
SMC解密结果如下
0x1000: mov dword ptr [ebp - 0x44], 0
0x1007: jmp 0x1012
0x1009: mov eax, dword ptr [ebp - 0x44]
0x100c: add eax, 1
0x100f: mov dword ptr [ebp - 0x44], eax
0x1012: cmp dword ptr [ebp - 0x44], 0x13
0x1016: jge 0x1041
0x1018: mov eax, dword ptr [ebp - 0x44]
0x101b: and eax, 0x80000001
0x1020: jns 0x1027
0x1022: dec eax
0x1023: or eax, 0xfffffffe
0x1026: inc eax
0x1027: test eax, eax
0x1029: je 0x103f
0x102b: mov eax, dword ptr [ebp + 8]
0x102e: add eax, dword ptr [ebp - 0x44]
0x1031: movsx ecx, byte ptr [eax]
0x1034: xor ecx, 4
0x1037: mov edx, dword ptr [ebp + 8]
0x103a: add edx, dword ptr [ebp - 0x44]
0x103d: mov byte ptr [edx], cl
0x103f: jmp 0x1009
即:
for (int i = 0; i < 0x13; i++)
{
if ((i + 1) % 2 == 0)
input[i] ^= 4
}
完整脚本
from ctypes import *
MAX = -1
save = [0] * 20; ans = [0] * 20
def dfs(h, l, sum):
global MAX, save, ans
sum += table[h * 100 + l]
if h == 20:
if sum >= MAX:
MAX = sum
ans = save[:]
return;
save[h] = 0
dfs(h + 1, l, sum)
save[h] = 1
dfs(h + 1, l + 1, sum)
if __name__ == '__main__':
msvcrt = cdll.msvcrt
msvcrt.srand(12)
table = [0]*100000
for i in range(1, 21):
for j in range(1, i + 1):
table[100 * i + j] = msvcrt.rand()
dfs(1, 1, 0)
instr = ''
for i in range(1, 20):
if ans[i] == 0:
instr += 'L'
else:
instr += 'R'
instr = [ord(c) for c in instr]
for i in range(len(instr)):
if (i + 1) % 2 == 0:
instr[i] ^= 4
instr = ''.join([chr(c) for c in instr])
print(instr)
Take the maze
打印迷宫的脚本如下
# -*- coding: UTF-8 -*-
def GetBox(offset):
box = []
with open('take_maze.exe', 'rb') as f:
data = f.read()[offset:offset + 312 * 4]
for i in range(0, len(data), 4):
tmp = data[i:i + 4]
tmp = tmp[::-1].encode('hex')
tmp = int(tmp, 16)
box.append(tmp)
return box
if __name__ == '__main__':
dev = 0x540548 - 0xe4148
DownBox0 = GetBox(0xe4148)
DownBox1 = GetBox(0x540068 - dev)
LeftBox0 = GetBox(0x5404dc - dev)
LeftBox1 = GetBox(0x53fffc - dev)
RightBox0 = GetBox(0x5404e4 - dev)
RightBox1 = GetBox(0x540004 - dev)
UpBox0 = GetBox(0x540478 - dev)
UpBox1 = GetBox(0x53FF98 - dev)
trait_maze = [0]*312
for i in range(12):
for j in range(26):
n = i * 26 + j
if DownBox0[n] == DownBox1[n]:
trait_maze[n] |= 1
if LeftBox0[n] == LeftBox1[n]:
trait_maze[n] |= 2
if RightBox0[n] == RightBox1[n]:
trait_maze[n] |= 4
if UpBox0[n] == UpBox1[n]:
trait_maze[n] |= 8
maze = ''
for i in range(12):
for j in range(26):
n = i * 26 + j
if trait_maze[n] & 1 == 1 and trait_maze[n] & 4 != 4:
maze += '↓'
elif trait_maze[n] & 4 == 4 and trait_maze[n] & 1 != 1:
maze += '-'
elif trait_maze[n] & (1 | 4) == 1 | 4:
maze += '+'
else:
maze += '0'
maze += '\n'
print maze
maze:
↓↓-↓---↓00↓↓↓↓↓↓↓↓↓↓↓0000-
-↓↓↓00-↓0-↓---------↓00000
↓↓-000-↓↓↓↓↓00000↓↓-↓0000-
-↓↓000-----↓0000--↓-000000
--↓↓↓↓↓↓↓0-↓↓↓↓↓↓↓↓↓↓00000
0---↓---↓0----------↓00000
000-↓00-↓0000000000-↓00000
000-↓00-↓↓↓↓↓000000↓↓00000
000-↓00-----↓00000--000000
000-↓000000-↓↓↓↓↓↓↓↓↓↓0000
000-0000000----------↓↓↓↓↓
00000000000000000000-----0
根据迷宫很容易构造输入06360836063b0839073e0639。