bugku逆向&安卓

入门逆向

嗯。

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。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值