0xgame re wk2 writeup

0xgame re wk2 wp

FirstSight-Pyc

直接在线反编译。

#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.8

import hashlib
user_input = input('请输入神秘代号:')
if user_input != 'Ciallo~':
    print('代号不是这个哦')
    exit()
input_hash = hashlib.md5(user_input.encode()).hexdigest()
input_hash = list(input_hash)
for i in range(len(input_hash)):
    if ord(input_hash[i]) in range(48, 58):
        original_num = int(input_hash[i])
        new_num = (original_num + 5) % 10
        input_hash[i] = str(new_num)
        continue
        input_hash = ''.join(input_hash)
        print('0xGame{{{}}}'.format(input_hash))
        return None

发现了Ciallo~发现好像跟逆向已经没什么关系了,只要改一改,正确输入,让程序跑出0xgame{xxx}就行了。

BabyUPX

upx -d脱壳,再打开可以看到加密,直接正向爆破。

ida encode部分:

__int64 __fastcall encode(_BYTE *a1)
{
  _BYTE *v2; // [rsp+8h] [rbp-8h]

  v2 = a1;
  if ( !*a1 )
    return 0xFFFFFFFFi64;
  do
  {
    *v2 = (16 * *v2) | (*v2 >> 4);
    ++v2;
  }
  while ( *v2 );
  return 0i64;
}

爆破:

#include<bits/stdc++.h>
using namespace std;
char encdata[] =
{
  0x03, 0x87, 0x74, 0x16, 0xD6, 0x56, 0xB7, 0x63, 0x83, 0x46, 
  0x66, 0x66, 0x43, 0x53, 0x83, 0xD2, 0x23, 0x93, 0x56, 0x53, 
  0xD2, 0x43, 0x36, 0x36, 0x03, 0xD2, 0x16, 0x93, 0x36, 0x26, 
  0xD2, 0x93, 0x73, 0x13, 0x66, 0x56, 0x36, 0x33, 0x33, 0x83, 
  0x56, 0x23, 0x66, 0xD7
};
char enc(char ch)
{
	return (ch*16) | (ch>>4);
}
int main()
{
    for(int i=0;i<44;i++)
     for(char ch=33;ch<=126;ch++)
      if(enc(ch)==encdata[i])
       {
       	 printf("%c",ch);
       	 break;
	   }
	return 0;
}
//0xGame{68dff458-29e5-4cc0-a9cb-971fec338e2f}

注意ida导出的时候使用的是usigned char,要改成char,不然部分字符没法显示。

FirstSight-Jar

java逆向,用jadx打开看。加密部分如下:

    private static String encrypt(String str) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            int indexOf = Alphabat.indexOf(str.charAt(i));
            if (indexOf < 0) {
                sb.append(str.charAt(i));
            } else {
                sb.append(Alphabat.charAt(((indexOf * 5) + 3) % 16));
            }
        }
        return sb.toString();
    }

Alphabat就是"0123456789abcdef",大意就是如果str的这一项不在Alphabat中就保留,否则加密,且加密后的字符也在Alphabat中。因此对str中所有在Alphabat中的字符进行爆破即可,将结果输入java程序他会用0xGame将其包裹。

#include<bits/stdc++.h>
using namespace std;
string en="ab50e920-4a97-70d1-b646-cdac5c873376";
char alp[]="0123456789abcdef";
int main()
{
	for(int i=0;i<en.length();i++)
	if(strchr(alp,en[i])==NULL)
	   cout<<en[i];
	else
	{
		for(int j=0;j<strlen(alp);j++)
		if(alp[((j * 5) + 3) % 16]==en[i])
	     {
	     	cout<<alp[j];
	     	break;
		 }
	}
	return 0;
}
//b8a9fe39-dbe4-4926-87d7-52b5a5140047

ZzZ

无壳,ida打开发现一大堆函数。这种情况下一般Shift+F12去找关键字符串,注意到Please enter your flag,X交叉引用来到关键代码:

往下看,可以看出下面有一系列对v11,v10,v12的约束,应该是判断flag的关键,但是前面sub_14001128F有点意义不明。结合%ll,%s格式控制符,猜测v13,v5,v6,v7,v14是flag中不同类型的部分(长整型和字符串)。

有了这个猜测再去看下面的约束,发现两个长整型部分已经给出,所以主要是解中间的三个字符串。这种比较复杂的约束一般考虑z3求解:

from z3 import *
v11 = BitVec('v11', 64)
v10 = BitVec('v10', 64)
v12 = BitVec('v12', 64)
constraints = [
    11 * v11 + 14 * v10 - v12 == 0x48FB41DDD,
    9 * v10 - 3 * v11 + 4 * v12 == 0x2BA692AD7,
    ((v12 - v11) >> 1) + (v10 ^ 0x87654321) == 3451779756
]
solver = Solver()
solver.add(constraints)
if solver.check() == sat:
    m = solver.model()
    print(f"v11 = {m[v11]}")
    print(f"v10 = {m[v10]}")
    print(f"v12 = {m[v12]}")

'''
v11 = 862073908
v10 = 842086455
v12 = 1681208161

'''

注意需要定义BitVec型未知数,不然右移和异或操作会报错。

当然这样还不算完,因为我们求解的是整型,需要转成字节串:

from Crypto.Util.number import long_to_bytes
v10 = 842086455
v11 = 862073908
v12 = 1681208161
print(long_to_bytes(v10)[::-1])
print(long_to_bytes(v11)[::-1])
print(long_to_bytes(v12)[::-1])
#有小端序存储转序问题,一开始没发现
'''
b'7812'
b'44b3'
b'a35d'
'''

自此就得到了flag的所有部分:

0xGame{e544267d-7812-44b3-a35d-d085a85201a4}

Xor::Ramdom

学习windows下C生成随机数rand(),srand(),其实是一种伪随机,当种子相同的时候生成的随机数实际上是一样的。

End

​ ——《月色真美》

posted @ 2024-10-21 19:41  brs7  阅读(6)  评论(0编辑  收藏  举报