目录
0x01 xx
测试文件:https://www.lanzous.com/i7dyqhc
1.准备
获取信息
- 64位文件
2.IDA打开
使用Findcrypt脚本可以看到
结合文件名是xx,因此猜测代码用到了xxtea加密方法
3.流程总结
因此,总的流程为:
- 判断输入的字符串的每个字符是否包含在"qwertyuiopasdfghjklzxcvbnm1234567890"中
- 取输入字符串的前4位字符,即"flag",扩展为16位,作为xxtea加密的秘钥key
- 将输入的字符串使用key加密,加密后的字符保存在字符数组v18,共24位字符
- 打乱v18数组,保存到v19数组中
- 将24位字符,每3位为一组,每一组异或值(具体看代码),得到新的加密字符串
- 将新的加密字符串与已经存在的字符串比较,相同即获得胜利
因此,只需要逆向变换,就能得到flag
使用动态调试,可以获取到已经存在的字符串
enc = 'CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA'
4.脚本解密
Python带了xxtea的包,不过我用的时候,一直提示我“ValueError: Need a 16-byte key.”,用rjust或者'\x00'*16补足了16位也不管用。
所以用了另外一种方法,借用了下面xxtea的文章:
参考文章:https://blog.csdn.net/weixin_41474364/article/details/84314674
# encoding: utf-8
import struct
_DELTA = 0x9E3779B9
def _long2str(v, w):
n = (len(v) - 1) << 2
if w:
m = v[-1]
if (m < n - 3) or (m > n): return ''
n = m
s = struct.pack('<%iL' % len(v), *v)
return s[0:n] if w else s
def _str2long(s, w):
n = len(s)
m = (4 - (n & 3) & 3) + n
s = s.ljust(m, "\0")
v = list(struct.unpack('<%iL' % (m >> 2), s))
if w: v.append(n)
return v
def encrypt(str, key):
if str == '': return str
v = _str2long(str, True)
k = _str2long(key.ljust(16, "\0"), False)
n = len(v) - 1
z = v[n]
y = v[0]
sum = 0
q = 6 + 52 // (n + 1)
while q > 0:
sum = (sum + _DELTA) & 0xffffffff
e = sum >> 2 & 3
for p in xrange(n):
y = v[p + 1]
v[p] = (v[p] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff
z = v[p]
y = v[0]
v[n] = (v[n] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[n & 3 ^ e] ^ z))) & 0xffffffff
z = v[n]
q -= 1
return _long2str(v, False)
def decrypt(str, key):
if str == '': return str
v = _str2long(str, False)
k = _str2long(key.ljust(16, "\0"), False)
n = len(v) - 1
z = v[n]
y = v[0]
q = 6 + 52 // (n + 1)
sum = (q * _DELTA) & 0xffffffff
while (sum != 0):
e = sum >> 2 & 3
for p in xrange(n, 0, -1):
z = v[p - 1]
v[p] = (v[p] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff
y = v[p]
z = v[n]
v[0] = (v[0] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[0 & 3 ^ e] ^ z))) & 0xffffffff
y = v[0]
sum = (sum - _DELTA) & 0xffffffff
return _long2str(v, True)
def xor(x ,y):
return ord(x) ^ ord(y)
# 转换为16进制
arr = 'CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA'.decode('hex')
dec = ''
# 因为加密时是正向加密,会用到加密之后的字符,因此解密需要逆向解密
for i in range(7,-1,-1):
res = ''
# 每3个为一组
for j in range(3):
temp = ord(arr[i*3+j])
# 需要异或的值,例如第i组的值就是,arr[i*3+j]^(arr[n] for n in range(i))
for m in range(i):
temp ^= ord(arr[m])
res += chr(temp)
dec = res + dec
# 原来的v18到v19数组是被打乱排序了的
num = [2,0,3,1,6,4,7,5,10,8,11,9,14,12,15,13,18,16,19,17,22,20,23,21]
enc = [0] * 24
# key需要是16位
key = 'flag'+'\x00'*12
for i in range(24):
enc[num[i]] = dec[i]
dec2 = ''.join(enc)
dec3 = decrypt(dec2, key)
print dec4
5.get flag!
flag{CXX_and_++tea}
0x02 easyRE
测试文件:https://share.weiyun.com/5qzM6bU
1.准备
获取信息
- 64位文件
2.IDA打开
signed __int64 sub_4009C6()
{
char *v0; // rsi
char *v1; // rdi
signed __int64 result; // rax
__int64 v3; // ST10_8
__int64 v4; // ST18_8
__int64 v5; // ST20_8
__int64 v6; // ST28_8
__int64 v7; // ST30_8
__int64 v8; // ST38_8
__int64 v9; // ST40_8
__int64 v10; // ST48_8
__int64 v11; // ST50_8
__int64 v12; // ST58_8
int i; // [rsp+Ch] [rbp-114h]
char arraym[36]; // [rsp+60h] [rbp-C0h]
char v15[32]; // [rsp+90h] [rbp-90h]
int v16; // [rsp+B0h] [rbp-70h]
char v17; // [rsp+B4h] [rbp-6Ch]
char v18; // [rsp+C0h] [rbp-60h]
char v19; // [rsp+E7h] [rbp-39h]
char v20; // [rsp+100h] [rbp-20h]
unsigned __int64 v21; // [rsp+108h] [rbp-18h]
v21 = __readfsqword(0x28u);
arraym[0] = 73;
arraym[1] = 111;
arraym[2] = 100;
arraym[3] = 108;
arraym[4] = 62;
arraym[5] = 81;
arraym[6] = 110;
arraym[7] = 98;
arraym[8] = 40;
arraym[9] = 111;
arraym[10] = 99;
arraym[11] = 121;
arraym[12] = 127;
arraym[13] = 121;
arraym[14] = 46;
arraym[15] = 105;
arraym[16] = 127;
arraym[17] = 100;
arraym[18] = 96;
arraym[19] = 51;
arraym[20] = 119;
arraym[21] = 125;
arraym[22] = 119;
arraym[23] = 101;
arraym[24] = 107;
arraym[25] = 57;
arraym[26] = 123;
arraym[27] = 105;
arraym[28] = 121;
arraym[29] = 61;
arraym[30] = 126;
arraym[31] = 121;
arraym[32] = 76;
arraym[33] = 64;
arraym[34] = 69;
arraym[35] = 67;
memset(v15, 0, sizeof(v15));
v16 = 0;
v17 = 0;
v0 = v15;
sub_4406E0(0LL, (__int64)v15);
v17 = 0;
v1 = v15;
if ( sub_424BA0(v15) == 36 )
{
for ( i = 0; ; ++i )
{
v1 = v15;
if ( i >= (unsigned __int64)sub_424BA0(v15) )
break;
if ( (unsigned __int8)(v15[i] ^ i) != arraym[i] )
{
result = 4294967294LL;
goto LABEL_13;
}
}
sub_410CC0("continue!");
memset(&v18, 0, 0x40uLL);
v20 = 0;
v0 = &v18;
sub_4406E0(0LL, (__int64)&v18);
v19 = 0;
v1 = &v18;
if ( sub_424BA0(&v18) == 39 )
{
v3 = sub_400E44(&v18);
v4 = sub_400E44(v3);
v5 = sub_400E44(v4);
v6 = sub_400E44(v5);
v7 = sub_400E44(v6);
v8 = sub_400E44(v7);
v9 = sub_400E44(v8);
v10 = sub_400E44(v9);
v11 = sub_400E44(v10);
v12 = sub_400E44(v11);
v0 = off_6CC090;
v1 = (char *)v12;
if ( !(unsigned int)sub_400360(v12, off_6CC090) )
{
sub_410CC0("You found me!!!");
v1 = "bye bye~";
sub_410CC0("bye bye~");
}
result = 0LL;
}
else
{
result = 4294967293LL;
}
}
else
{
result = 0xFFFFFFFFLL;
}
LABEL_13:
if ( __readfsqword(0x28u) != v21 )
sub_444020(v1, v0);
return result;
}
3.代码分析
首先有两次输入,第一次输入32位字符串,将每位字符异或后与已存在的marray数组比较,因此可以写出脚本,正确输入
arr = [73,111,100,108,62,81,110,98,40,111,99,121,127,121,46,105,127,100,96,51,119,125,
119,101,107,57,123,105,121,61,126,121,76,64,69,67]
dec = ''
for i in range(36):
dec += chr(arr[i]^i)
print(dec)
Info:The first four chars are `flag`
第二次输入,将输入的字符串进行10次base64加密后,与已知的字符串比较,反向解密就行
enc = "Vm0wd2VHUXhTWGhpUm1SWVYwZDRWVll3Wkc5WFJsbDNXa1pPVlUxV2NIcFhhMk0xVmpKS1NHVkdXbFpOYmtKVVZtcEtTMUl5VGtsaVJtUk9ZV3hhZVZadGVHdFRNVTVYVW01T2FGSnRVbGhhVjNoaFZWWmtWMXBFVWxSTmJFcElWbTAxVDJGV1NuTlhia0pXWWxob1dGUnJXbXRXTVZaeVdrWm9hVlpyV1hwV1IzaGhXVmRHVjFOdVVsWmlhMHBZV1ZSR1lWZEdVbFZTYlhSWFRWWndNRlZ0TVc5VWJGcFZWbXR3VjJKSFVYZFdha1pXWlZaT2NtRkhhRk5pVjJoWVYxZDBhMVV3TlhOalJscFlZbGhTY1ZsclduZGxiR1J5VmxSR1ZXSlZjRWhaTUZKaFZqSktWVkZZYUZkV1JWcFlWV3BHYTFkWFRrZFRiV3hvVFVoQ1dsWXhaRFJpTWtsM1RVaG9hbEpYYUhOVmJUVkRZekZhY1ZKcmRGTk5Wa3A2VjJ0U1ExWlhTbFpqUldoYVRVWndkbFpxUmtwbGJVWklZVVprYUdFeGNHOVhXSEJIWkRGS2RGSnJhR2hTYXpWdlZGVm9RMlJzV25STldHUlZUVlpXTlZadE5VOVdiVXBJVld4c1dtSllUWGhXTUZwell6RmFkRkpzVWxOaVNFSktWa1phVTFFeFduUlRhMlJxVWxad1YxWnRlRXRXTVZaSFVsUnNVVlZVTURrPQ=="
for i in range(10):
enc = enc.decode('base64')
print (enc)
https://bbs.pediy.com/thread-254172.htm
在第二次输入加密后对比的常量下面,还发现了一个常量,在sub_400D35函数中调用
__int64 __fastcall sub_400D35(__int64 a1, __int64 a2)
{
__int64 v2; // rdi
__int64 result; // rax
unsigned __int64 v4; // rt1
unsigned int v5; // [rsp+Ch] [rbp-24h]
signed int i; // [rsp+10h] [rbp-20h]
signed int j; // [rsp+14h] [rbp-1Ch]
unsigned int v8; // [rsp+24h] [rbp-Ch]
unsigned __int64 v9; // [rsp+28h] [rbp-8h]
v9 = __readfsqword(0x28u);
v2 = 0LL;
v5 = sub_43FD20(0LL) - qword_6CEE38;
for ( i = 0; i <= 1233; ++i )
{
v2 = v5;
sub_40F790(v5);
sub_40FE60();
sub_40FE60();
v5 = (unsigned __int64)sub_40FE60() ^ 0x98765432;
}
v8 = v5;
if ( ((unsigned __int8)v5 ^ byte_6CC0A0[0]) == 'f' && (HIBYTE(v8) ^ (unsigned __int8)byte_6CC0A3) == 'g' )
{
for ( j = 0; j <= 24; ++j )
{
v2 = (unsigned __int8)(byte_6CC0A0[j] ^ *((_BYTE *)&v8 + j % 4));
sub_410E90(v2);
}
}
v4 = __readfsqword(0x28u);
result = v4 ^ v9;
if ( v4 != v9 )
sub_444020(v2, a2);
return result;
}
两段异或,第一段异或,能够通过'flag'和已知数组反向解出v5
第二段异或。通过已知数组和v5解出flag
key = ''
enc1 = 'flag'
dec = ''
enc = [0x40,0x35,0x20,0x56,0x5D,0x18,0x22,0x45,0x17,0x2F,0x24,0x6E,0x62,0x3C,0x27,0x54,0x48,0x6C,0x24,0x6E,0x72,0x3C,0x32,0x45,0x5B]
for i in range(4):
key += chr(enc[i] ^ ord(enc1[i]))
print (key)
for i in range(len(enc)):
dec += chr(enc[i] ^ ord(key[i%4]))
print(dec)
4.get flag!
flag{Act1ve_Defen5e_Test}
0x03 calc
测试文件:https://www.lanzous.com/i7frprg
1准备
获取信息
- 64位文件
2.IDA打开
伪C代码
3.流程总结
整个过程,有三次输入,定义为变量x, y, z。在满足x < z and x > y的条件下,进行x**3+y**3+z**3=42,搜了一下有关“三次方42”的新闻
得到
(-80538738812075974)^3 + 80435758145817515^3 + 12602123297335631^3 = 42
根据x,y,z关系式得到
x=80435758145817515
y=12602123297335631
z=80538738812075974
将Sleep的时间全部改为0
写出脚本得到flag
4.get flag!
flag{951e27be2b2f10b7fa22a6dc8f4682bd}
0x04 childRE
测试文件:https://www.lanzous.com/i7h66wd
1.准备
- 64位文件
2.IDA代码分析
3.流程总结
- 因此总的运算流程就是:
- 输入长度为31的字符串
- 进行置换运算
- 取消修饰函数名
- 将未修饰函数名的商和余数与指定字符串比较
我们能够逆向操作来得到未修饰的函数名。
4.获取未修饰函数名
IDA动态调试
写出脚本
str1 = "(_@4620!08!6_0*0442!@186%%0@3=66!!974*3234=&0^3&1@=&0908!6_0*&"
str2 = "55565653255552225565565555243466334653663544426565555525555222"
str3 = '1234567890-=!@#$%^&*()_+qwertyuiop[]QWERTYUIOP{}asdfghjkl;,ASDFGHJKL:"ZXCVBNM<>?zxcvbnm,./'
name = ''
for i in range(62):
name += chr(str3.index(str1[i]) + str3.index(str2[i])*23 )
print (name)
得到:private: char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)
使用C++写出一个上面函数的例子:
#include <iostream>
class R0Pxx {
public:
R0Pxx() {
My_Aut0_PWN((unsigned char*)"hello");
}
private:
char* __thiscall My_Aut0_PWN(unsigned char*);
};
char* __thiscall R0Pxx::My_Aut0_PWN(unsigned char*) {
std::cout << __FUNCDNAME__ << std::endl;
return 0;
}
int main()
{
R0Pxx A;
system("PAUSE");
return 0;
}
得到:?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z
5.置换运算
通过动态调试,发现乱序取值的数值是固定的,因此随便输入一组长度31的字符串(其中的字符不能重复)
反向操作,写出脚本来解决flag
from hashlib import md5
str1 = 'abcdefghijklmnopqrstuvwxyz12345'
dec1 = '7071687273696474756A76776B656278796C7A316D6632336E34356F676361'.decode('hex')
serial = []
print dec1
for i in dec1:
serial.append(str1.index(i))
print serial
name = '?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z'
enc = [''] * 31
for i in range(31):
enc[serial[i]] = name[i]
enc = ''.join(enc)
print enc
print md5(enc).hexdigest()
6.get flag!
flag{63b148e750fed3a33419168ac58083f5}
0x05 Snake
测试文件:https://www.lanzous.com/i7gol0d
Unity逆向
1.查看DLL文件
运行Snake,查看调用的DLL文件
2.DLL文件分析
使用ILSpy打开Interface.dll文件
发现了DLL文件使用的函数GameObject
使用IDA打开DLL文件
GameObject
判断出GameObject函数传入的参数,最大应该是199,因此直接写程序,调用DLL文件,爆破求flag
3.爆破求解
开多个进程,同时求解。
#include <Windows.h>
#include <iostream>
#include <libloaderapi.h>
using namespace std;
int main(int argc, char* argv[])
{
const char* funcName = "GameObject";
HMODULE hDLL = LoadLibrary(TEXT("C:\\Users\\10245\\Desktop\\Snake\\Snake_Data\\Plugins\\Interface.dll"));
if (hDLL != NULL)
{
cout << "Load Success!" << endl;
typedef int(_cdecl *FuncPtr)(int);
FuncPtr func = (FuncPtr)GetProcAddress(hDLL, funcName);
func(atoi(argv[1]));
}
else
{
cout << "Load Failed!" << endl;
}
system("PAUSE");
return 0;
}
4.get flag!
flag{Ch4rp_W1th_R$@}
作者:Hk_Mayfly
出处:https://www.cnblogs.com/Mayfly-nymph/
个人博客:hkmayfly.com
CSDN:https://blog.csdn.net/qq_39542714
如果你觉得博客对你有帮助的话,可以给博主一个(づ ̄3 ̄)づ╭❤~赞或者关注,谢谢!
博主目前大部分写作在博客园,欢迎大家来访,( ̄︶ ̄)↗也欢迎爱好写作的朋友和我交换友链。
附注:不支持转载!欢迎大家加我QQ,互相交流。Biubiubiu~顺便来关注我的公众号:Star Bottle叭!,哈哈哈!
来源:CSDN
作者:Hk_Mayfly
链接:https://blog.csdn.net/qq_39542714/article/details/103235530