GeekChallenge_REVERSE Writeup
Shift_jmp | 简单花指令

将无条件跳转和loc_117Apatch为nop重构主函数

简单的异或加密 解题Python脚本如下
key = [83, 88, 65, 120, 83, 54, 106, 100, 56, 100,
111, 84, 120, 66, 81, 123, 120, 34, 77, 97,
39, 99, 115, 69, 45, 124, 69, 108, 44, 111,
47, 123, 94, 92]
for i in range(34):
print(chr(key[i] ^ i ^ 0), end='')
#SYC{W3lc0me_tO_th3_r3veR5e_w0r1d~}
点击就送的逆向题 | C源码的编译
.s文件是由C源码编译而来的汇编指令 它与.S文件的区别是它不支持预处理(#define...) gcc编译器可以将其经过链接等再编译为可执行文件 故可以先将.s文件编译为可执行文件再用IDA分析
clang click.s -o click
Kali虚拟机预装的gcc编译器用以上指令可以直接将.s文件编译为Linux可执行文件

简单的位移加密 解题Python脚本如下
key = 'Z`J[X^LMNO`PPJPVQRSIUTJ]IMNOZKMM' for each in key: print(chr(ord(each) - 7), end='') # SYCTQWEFGHYIICIOJKLBNMCVBFGHSDFF
Easymath | z3-solver简单使用
Exinfo查到无壳 64位win程序 IDA64打开

-
check函数逻辑简单 不分析(
-
checkposition函数逻辑也简单 不分析(
-
exchange函数

不理解 26行之前的代码作用 但是并不影响分析(
number在内存空间中每个有效元素之间插入三个0

与代码中的p_number[i] = number_[4 * v10]对应 最后一个循环的作用就是将字符在table中的位置映射到这些有效元素上
回到主函数 主要的比较逻辑就是经过映射后的position作为一个5阶方阵与另一个5阶方阵matrix用特殊的矩阵乘法法则相乘得到的矩阵与单位矩阵相比 以下是Python代码实现 其中n为矩阵的阶数
for i in range(n):
for j in range(n):
result[i][j] = 0
for k in range(n):
result[i][j] = (M1[i][k] * M2[k][j] + result[i][j]) % 0x20
除此之外主函数中还能看到为了防止出现多解给出的flag提示(动态调试时发现其为flag中的元素 重构为数组可以将变量名从内存地址变为数组) 可以使用爆破的方式解出flag 也可以使用z3-solver库解出
from z3 import *
table = '01234_asdzxcpoityumnbAOZWXGMY'
matrix = [18, 29, 16, 19, 27,
8, 31, 8, 23, 30,
29, 3, 28, 10, 21,
18, 29, 8, 16, 28,
11, 30, 7, 20, 7]
v7 = [1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1]
num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 19, 22, 26, 27, 28, 29, 31, 32, 50, 51, 52, 53, 54, 55, 56]
for w in range(5):
mysolver = Solver()
position = IntVector('position', 5)
if w == 0:
mysolver.add(position[1] == 19)
elif w == 1:
mysolver.add(position[2] == 22)
elif w == 3:
mysolver.add(position[2] == 22)
mysolver.add(And([Or([position[i] == val for val in num]) for i in range(5)]))
for j in range(5):
expr = IntVal(0)
for k in range(5):
expr = (expr + position[k] * matrix[5 * k + j]) % 0x20
mysolver.add(expr == v7[5 * w + j])
result = mysolver.check()
if result == sat:
m = mysolver.model()
position_values = [m[position[i]].as_long() for i in range(5)]
for each in position_values:
print(table[num.index(each)], end='')
#xtd4co_ymiunbbx3Aypsmbzii
else:
print('No solution')
需要注意的是 可以一次性爆破全部不确定的22个元素 但这样会使复杂度提升到29^22(我猜的) 而每一次运算只用到position中的一行元素 故可以一行一行地爆破 可以将复杂度降低到5*29^5(我猜的)所以选择一行一行爆破(z3学习笔记另写)
luck | 简单爆破
Exinfo查到无壳 64位win程序 IDA64打开

主函数定义了一个unsigned __int8类型地数组 这个数据类型的大小和char一样 qmemcpy(cmp_data, "\r\a", 2);这句实际上只将"\r\a"中地前两个字符复制到了cmp_data的末尾 数组名代表首元素地址 所以
cmp_data[0] = '\'
cmp_data[1] = 'r'
同理

将"o96*#"添加到了cmp_data的第37个元素及之后
(其实最简单的方式是动态调试直接查看cmp_data中的数据)
主函数中的加密函数为用递归实现的等差数列求和

不管输入的数字是什么都会输出加密后的密文 根据flag前3个固定的字符爆破flag
key = [13, 7, 29]
for i in range(1000):
result = int(i * (i + 1) / 2) % 0xD3
if key[0] ^ (result) == ord('S') and key[1] ^ (result) == ord('Y') and key[2] ^ (result) == ord('C'):
print(i)
# 69
break
在程序中输入数字得到flag
砍树 | 安卓逆向
主函数的逻辑很简单

就是调用一个函数传入输入的字符串和key 判断返回值 这个函数在ezreeee库中 导出这个库用IDA分析


在函数列表中检索I0o0I函数 传入的参数有4个 其中有2个是JNIEnv和jobject JNI是为了让JAVA和C/C++互通构建的环境 jxxxxx是为了不与C原有的类型冲突 所以从下面的2个jstring_2unsigchar函数也可以看出a3和a4分别为jeb伪代码中看到的两个参数与加密后的输入对比的是从内存0x14900中复制的35个字节型数据 以下是解密脚本
key = [0, 32, 32, 23, 27, 54, 14, 54, 38, 23,
4, 42, 41, 7, 38, 21, 82, 51, 45, 15,
58, 39, 17, 6, 51, 7, 70, 23, 61, 10,
60, 56, 46, 34, 24, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0]
to_mod = "Sycloverforerver"
i = 0
for each in key:
print(chr(each ^ ord(to_mod[i % 7])), end='')
i += 1
#SYC{t@ke_thE_bul1_By_the_h0rns_TAT}SycloveSyclov
听说cpp很难? | C++逆向
Exinfo查到无壳 64位win程序 IDA64打开 伪代码如下
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rax
unsigned __int64 v4; // rbx
__int64 v5; // rax
_BYTE *addr_nowChar; // rax
unsigned int now_char; // ebx
_BYTE *v8; // rsi
int v9; // ebx
int v10; // ebx
__int64 v11; // rax
__int64 v12; // rax
__int64 m; // [rsp+20h] [rbp-60h] BYREF
__int64 k; // [rsp+28h] [rbp-58h] BYREF
char copy_flag[32]; // [rsp+30h] [rbp-50h] BYREF
char be_encoded[48]; // [rsp+50h] [rbp-30h] BYREF
_BYTE enc[32]; // [rsp+80h] [rbp+0h] BYREF
int v19[40]; // [rsp+A0h] [rbp+20h] BYREF
char input_flag[40]; // [rsp+140h] [rbp+C0h] BYREF
__int64 v21; // [rsp+168h] [rbp+E8h] BYREF
__int64 v22; // [rsp+170h] [rbp+F0h] BYREF
unsigned int len; // [rsp+17Ch] [rbp+FCh]
int v24; // [rsp+180h] [rbp+100h]
int v25; // [rsp+184h] [rbp+104h]
int j; // [rsp+188h] [rbp+108h]
int i; // [rsp+18Ch] [rbp+10Ch]
_main(argc, argv, envp);
v3 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "place input your flag:");
std::ostream::operator<<(v3, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
std::string::basic_string(input_flag);
memset(v19, 0, sizeof(v19));
v19[0] = 0x4D;
v19[1] = 0x5F;
v19[2] = 0x3D;
v19[3] = 0xFFFFFF85;
v19[4] = 0x37;
v19[5] = 0x68;
v19[6] = 0x73;
v19[7] = 0x57;
v19[8] = 0x27;
v19[9] = 0x68;
v19[10] = 0x51;
v19[11] = 0x59;
v19[12] = 0x7F;
v19[13] = 0x26;
v19[14] = 0x6B;
v19[15] = 0x59;
v19[16] = 0x73;
v19[17] = 0x57;
v19[18] = 0x55;
v19[19] = 0x5B;
v19[20] = 0x59;
v19[21] = 0x6F;
v19[22] = 0x6A;
v19[23] = 0x59;
v19[24] = 0x27;
v19[25] = 0x57;
v19[26] = 0x72;
v19[27] = 0x57;
v19[28] = 0x4F;
v19[29] = 0x57;
v19[30] = 0x78;
v19[31] = 0x78;
v19[32] = 0xFFFFFF83;
std::operator>><char>(refptr__ZSt3cin, input_flag);
len = std::string::size(input_flag);
std::vector<int>::vector(enc);
for ( i = 0; ; ++i )
{
std::vector<int>::push_back(enc, &v19[i]);
if ( i > 34 )
break;
} // 复制v19到enc中
encode::encode(be_encoded, len, input_flag, 10);//
// be_encoded[0] = len(flag)
// be_encoded[8...] = input_flag
// be_encoded[40] = 10
// be_encoded[44] = 10
std::vector<char>::vector(copy_flag);
for ( j = 0; ; ++j )
{
v4 = j;
if ( v4 >= std::string::size(input_flag) )
break;
v5 = std::string::operator[](input_flag, j);// v5 = input_flag[j]
std::vector<char>::push_back(copy_flag, v5);
}
v25 = 0;
for ( k = std::vector<char>::begin(copy_flag);// for k in copy_flag
;
__gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator++(&k, 0i64) )
{
v21 = std::vector<char>::end(copy_flag);
if ( !__gnu_cxx::operator!=<char *,std::vector<char>>(&k, &v21) )// 读到最后一个字符时退出
break;
addr_nowChar = __gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&k);
*addr_nowChar += be_encoded[44];
now_char = *__gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&k);
v8 = __gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&k);
*v8 = text_67(be_encoded, now_char); // now_char += 10
// now_char = (10 ^ now_char) - 10
// now_char = v19[i]
}
v24 = 0;
for ( m = std::vector<char>::begin(copy_flag);
;
__gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator++(&m, 0i64) )
{
v22 = std::vector<char>::end(copy_flag);
if ( !__gnu_cxx::operator!=<char *,std::vector<char>>(&m, &v22) )
break;
v9 = *__gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&m);
if ( v9 == *std::vector<int>::operator[](enc, v24) )
++v25;
v10 = *__gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&m);
if ( v10 != *std::vector<int>::operator[](enc, v24) )
--v25;
++v24;
}
if ( v25 > 32 ) // v25统计正确的字符
{
v11 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "yes yes you are right!");
std::ostream::operator<<(v11, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
}
if ( v25 <= 32 )
{
v12 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "no try again~");
std::ostream::operator<<(v12, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
}
std::vector<char>::~vector(copy_flag);
encode::~encode(be_encoded);
std::vector<int>::~vector(enc);
std::string::~string(input_flag);
return 0;
}
分析C++逆向时XXXXXXXoperatorxxx(a, b) 可以看作a对b做xxx操作
其中的主要逻辑是先对be_encoded进行encode操作 进入查看

需要注意的是主函数中定义的be_encoded储存的数据长度为1byte 而C++中的双字类型长度为4bytes 所以其中的下标转化到原来的be_encoded中需要乘上4 text_67的逻辑很简单
__int64 __fastcall text_67(__int64 be_encoded, char now_char)
{
*(be_encoded + 40) = 9;
return (((*(be_encoded + 40) + 1) ^ now_char) - *(be_encoded + 40) - 1);
}
剩下的对比逻辑也很简单 以下是解密脚本
enc = [None] * 33
enc[0] = 77
enc[1] = 95
enc[2] = 61
enc[3] = 0x85
enc[4] = 55
enc[5] = 104
enc[6] = 115
enc[7] = 87
enc[8] = 39
enc[9] = 104
enc[10] = 81
enc[11] = 89
enc[12] = 127
enc[13] = 38
enc[14] = 107
enc[15] = 89
enc[16] = 115
enc[17] = 87
enc[18] = 85
enc[19] = 91
enc[20] = 89
enc[21] = 111
enc[22] = 106
enc[23] = 89
enc[24] = 39
enc[25] = 87
enc[26] = 114
enc[27] = 87
enc[28] = 79
enc[29] = 87
enc[30] = 120
enc[31] = 120
enc[32] = 0x83
for i in range(33):
print(chr(((enc[i] + 10) ^ 10) - 10), end='')
# SYC{Anma1nG_y0u_maKe_it_1alaIa~~}
flower-or-tea | 简单花指令和TEA加密
Exinfo查到无壳 32位win程序 IDA32打开 伪代码如下
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [esp+0h] [ebp-1B0h]
char v5; // [esp+0h] [ebp-1B0h]
char v6; // [esp+0h] [ebp-1B0h]
char v7; // [esp+0h] [ebp-1B0h]
int v8[40]; // [esp+Ch] [ebp-1A4h]
unsigned int _54; // [esp+ACh] [ebp-104h]
int v10; // [esp+B0h] [ebp-100h]
char *v11; // [esp+B4h] [ebp-FCh]
int lenth; // [esp+B8h] [ebp-F8h]
char *v13; // [esp+BCh] [ebp-F4h]
int j; // [esp+C0h] [ebp-F0h]
int i; // [esp+C4h] [ebp-ECh]
int v16[40]; // [esp+CCh] [ebp-E4h]
int v17[4]; // [esp+16Ch] [ebp-44h] BYREF
int v18; // [esp+17Ch] [ebp-34h] BYREF
int v19; // [esp+180h] [ebp-30h]
char input[40]; // [esp+184h] [ebp-2Ch] BYREF
int v21; // [esp+1ACh] [ebp-4h]
int savedregs; // [esp+1B0h] [ebp+0h] BYREF
v17[0] = 32;
v17[1] = 27;
v17[2] = 39;
v17[3] = 44;
memset(input, 0, sizeof(input));
print(&Format, v4);
print(&byte_CA409C, v5);
print(&byte_CA4090, v6);
scanf(aS, input);
v11 = &input[1];
v13 = &input[strlen(input) + 1];
v10 = v13 - &input[1];
lenth = v13 - &input[1];
_54 = 54;
v16[0] = -1694939573;
v16[1] = -1005078370;
v16[2] = -1307072749;
v16[3] = -918836760;
v16[4] = -1795955634;
v16[5] = -1244910923;
v16[6] = 1146217516;
v16[7] = 2055874714;
v16[8] = 1405669384;
v16[9] = 1846639433;
v16[10] = -1677731948;
v16[11] = 1593781753;
v16[12] = 401024305;
v16[13] = -541222535;
v16[14] = -1886971078;
v16[15] = 1944634796;
v16[16] = -1299812186;
v16[17] = 1526113129;
v16[18] = 754440740;
v16[19] = 880502447;
v16[20] = -1178055328;
v16[21] = -1860267729;
v16[22] = -1118163045;
v16[23] = -879332550;
v16[24] = -979801922;
v16[25] = -1610607639;
v16[26] = -1053864284;
v16[27] = -561628656;
v16[28] = -1597713004;
v16[29] = 1132501052;
v16[30] = 2117039688;
v16[31] = -447882103;
v16[32] = 1059563152;
v16[33] = -1249037927;
v16[34] = 1615521047;
v16[35] = -1668269692;
v16[36] = -186628991;
v16[37] = 1022684671;
v16[38] = 0;
v16[39] = 0;
if ( v13 - &input[1] == 38 ) // flag长度为38
{
if ( input[0] == 83 && input[1] == 89 && input[2] == 67 )
{
if ( input[3] == 123 && input[37] == 125 )
{
for ( i = 0; i < lenth / 2; ++i )
{
v18 = input[i];
v19 = input[lenth - i - 1];
sub_CA10C3(_54, &v18, v17);
v8[2 * i] = v18; // 奇数元素
v8[2 * i + 1] = v19; // 偶数元素
} // target:v8 = v16
for ( j = 0; j < lenth && v8[j] == v16[j]; ++j )
;
if ( j == lenth )
{
print(aYesYes, v7);
system(aPause_1);
}
else
{
print(aWrong, v7);
system(aPause_2);
}
}
else
{
print(&byte_CA4060, v7);
system(aPause_0);
}
}
else
{
print(aFlag, v7);
system(aPause_3);
}
}
else
{
print(&byte_CA407C, v7);
system(Command);
}
return sub_CA15D1(&savedregs ^ v21);
}
核心逻辑就是输入的数据加密后调换顺序并和v16比较 这个加密算法(sub_CA10C3)就是TEA加密 特点是没有数据丢失 可以逆向

需要注意的是传入的第二个参数是主函数中的&v18 打开v18栈中的位置 发现v19就是紧挨其的下一个

所以v5 = now_char[1];这句实际上取的是v19
另外一点需要注意的是数据的上限 unsigned int类型的数据最多储存4bytes 故每次执行都需要截去高32位
知道这些后就可以写出以下解密脚本
from z3 import *
key = [None] * 4
key[0] = 32
key[1] = 27
key[2] = 39
key[3] = 44
enc = [None] * 38
enc[0] = 0x9AF9464B
enc[1] = 0xC417B89E
enc[2] = 0xB217A713
enc[3] = 0xC93BA9E8
enc[4] = 0x94F3E44E
enc[5] = 0xB5CC2AB5
enc[6] = 0x4451E42C
enc[7] = 0x7A8A289A
enc[8] = 0x53C8D008
enc[9] = 0x6E117B49
enc[10] = 0x9BFFD794
enc[11] = 0x5EFF2DF9
enc[12] = 0x17E72531
enc[13] = 0xDFBD9979
enc[14] = 0x8F871B3A
enc[15] = 0x73E8C5AC
enc[16] = 0xB28670A6
enc[17] = 0x5AF6A369
enc[18] = 0x2CF7DA24
enc[19] = 0x347B66AF
enc[20] = 0xB9C84D60
enc[21] = 0x911E912F
enc[22] = 0xBD5A2F9B
enc[23] = 0xCB96733A
enc[24] = 0xC59968BE
enc[25] = 0xA00013E9
enc[26] = 0xC12F4EA4
enc[27] = 0xDE863A10
enc[28] = 0xA0C4D594
enc[29] = 0x4380983C
enc[30] = 0x7E2F7648
enc[31] = 0xE54DDC89
enc[32] = 0x3F27A690
enc[33] = 0xB58D3199
enc[34] = 0x604AE517
enc[35] = 0x9C903984
enc[36] = 0xF4E04481
enc[37] = 0x3CF4EDFF
flag = [None] * 38
lenth = 38
for i in range(19):
flag[i] = enc[2 * i]
flag[lenth - i - 1] = enc[2 * i + 1]
delta = 54 * 0x31415927
for _ in range(54):
delta -= 0x31415927
flag[i] -= (key[delta % 4] + delta) ^ (flag[lenth - i - 1] + ((flag[lenth - i - 1] >> 5) ^ (16 * flag[lenth - i - 1])))
flag[i] &= 0xFFFFFFFF
flag[lenth - i - 1] -= delta ^ (key[(delta >> 11) % 4] + delta) ^ (flag[i] + ((flag[i] >> 5) ^ (16 * flag[i])))
flag[lenth - i - 1] &= 0xFFFFFFFF
for each in flag:
print(chr(each), end='')
# SYC{D0_Yov_1ike_To_dRink_Flow3r_teA??}
rainbow | 控制流平坦化
关于去控制流平坦化参考 利用符号执行去除控制流平坦化 - 博客 - 腾讯安全应急响应中心
这里用别人的工具脚本去平坦化 去平坦化后的代码如下

由于判断无用块的方法是排除法(排除掉序言块,分发器,预处理块和返回块) 而原程序中退出并不使用return而是call exit 所以被判定为无用块被删除 故判断长度和flag不正确就退出的块被删去 观察原来的代码 剩下的代码就是加密后的flag和v8~v11的数据进行对比 解密脚本如下
key = [101, 88, 65, 142, 80, 68, 123, 98, 87, 74,
126, 84, 73, 108, 125, 132, 79, 91, 149, 96,
96, 100, 119, 72, 125, 77, 123, 159, 104, 60,
45, 98]
for i in range(32):
key[i] ^= i
key[i] -= 18 * (i % 3 == 0)
print(chr(key[i]), end='')
# SYC{TAke_1t_3asy_Just_a_STart!!}
mySelf | 简单SMC
Exinfo查到无壳 32位win程序 IDA32打开

VirtualProtect函数给予一段内存地址(函数)修改自身字节码的权限 基本上是SMC的标志
如果不使用静态分析的方法可以直接动态调试 这样的可操作性高 在SMC的函数下断点 动态调试到断点处 F7步进函数 之后查看汇编代码 将SMC后的函数重新识别为函数再反编译为伪代码分析
unsigned int __cdecl encode(int a1)
{
int v1; // ebx
int v2; // edi
unsigned int v3; // esi
int v4; // ebx
unsigned int result; // eax
unsigned int *v6; // [esp+Ch] [ebp-Ch]
unsigned int *v7; // [esp+10h] [ebp-8h]
int v8; // [esp+14h] [ebp-4h]
v1 = 0;
v8 = 0;
do
{
v2 = 0;
v3 = *(_DWORD *)(a1 + 4 * v1);
v7 = (unsigned int *)(a1 + 4 * v1);
v6 = (unsigned int *)(a1 + 4 * (v1 + 1));
v4 = 32;
result = *v6;
do
{
v2 -= 1640531527;
v3 += ((result >> 5) + 2) ^ (16 * result + 2) ^ (v2 + result);
result += ((v3 >> 5) + 4) ^ (16 * v3 + 3) ^ (v2 + v3);
--v4;
}
while ( v4 );
v8 += 2;
v1 = v8;
*v7 = v3;
*v6 = result;
}
while ( v8 < 8 );
return result;
}
又是一个TEA加密 但是其中用到了一个伪随机数 需要动态调试获得 这个TEA加密和上一题中的不同点是每次被加密的字符顺序不同 同时也要注意每次加密的数据长度是4bytes 而原来传入的是以1byte分割的数组的地址 而在x86程序中双字型数据使用小端序储存 知道了这些之后写出解密脚本
o_key = [0xF0, 0xF9, 0xBD, 0xBD, 0xC4, 0x94, 0x61, 0xE2, 0x25, 0x91,
0x79, 0x80, 0x19, 0xC2, 0x0F, 0x1F, 0x15, 0x18, 0x6A, 0xEB,
0xC5, 0x72, 0xF5, 0x84, 0x85, 0x3A, 0xCC, 0x40, 0xBB, 0x2A,
0xA3, 0xD2]
flag = []
for i in range(8):
flag.append(o_key[4 * i] | o_key[4 * i + 1] << 8 | o_key[4 * i + 2] << 16 | o_key[4 * i + 3] << 24)
for i in range(4):
v2 = 0x61C88647 * (-32)
for _ in range(32):
flag[2 * i + 1] -= ((flag[2 * i] >> 5) + 4) ^ (16 * flag[2 * i] + 3) ^ (v2 + flag[2 * i])
flag[2 * i + 1] &= 0xFFFFFFFF
flag[2 * i] -= ((flag[2 * i + 1] >> 5) + 2) ^ (16 * flag[2 * i + 1] + 2) ^ (v2 + flag[2 * i + 1])
flag[2 * i] &= 0xFFFFFFFF
v2 += 0x61C88647
for each in flag:
for i in range(4):
print(chr((each >> (8 * i)) & 0xFF), end='')
小黄鸭 | Python逆向
Exinfo 查到为Python3.7写的程序 可以先用pyinstxtractor将其反汇编生成.pyc文件 再用uncompyle6进行反编译生成.py文件
python pyinstxtractor.py duck.exe uncompyle6.exe 1.pyc > duck.py
没有进行混淆
# --------duck.py----------
# uncompyle6 version 3.7.4
# Python bytecode 3.7 (3394)
# Decompiled from: Python 3.11.4 (tags/v3.11.4:d2340ef, Jun 7 2023, 05:45:37) [MSC v.1934 64 bit (AMD64)]
# Embedded file name: 1.py
import sys
arr = '~h|p4gs`gJdN`thPwR`jDn`te1w`2|RNH'
arr = list(arr)
print('快帮帮小黄鸭,找到它的钥匙')
a = input('请输入你找到的钥匙>:')
a = list(a)
if not ord(a[0]) != 83:
if ord(a[1]) != 89 or ord(a[2]) != 67:
print('不对喔~')
sys.exit(0)
a = a[::-1]
b = []
for i in range(len(a)):
if a[i].isalpha():
c = a[i]
c = chr(ord(c) + 13 - 26 if ord(c) + 13 > (90 if c <= 'Z' else 122) else ord(c) + 13)
b.append(chr(ord(c) + 2))
else:
b.append(chr(ord(a[i]) + 1))
if chr(ord(a[1])) != 's' or ord(a[2]) != 109 or chr(ord(a[17])) != 'C':
print('呀呀呀,怎么算出来不对呀?')
sys.exit(0)
cnt = 0
for i in range(len(b)):
if arr[i] == b[i]:
cnt += 1
if cnt == len(b):
print('密码正确啦!!!,快去告诉小黄鸭吧~')
else:
print('密码不对喔~,请再想想吧')
# okay decompiling 1.pyc
简单的ROT13加密 写出脚本解密
key_o = '~h|p4gs`gJdN`thPwR`jDn`te1w`2|RNH'
key_o = list(key_o)
key_o = key_o[::-1]
key = [ord(val) for val in key_o]
for each in key:
if(chr(each - 2).isalpha()):
c = each -2
c += 13 if ord('a') <= c and c <= ord('m') or ord('A') <= c and c <= ord('M') else (-13)
print(chr(c), end='')
else:
print(chr(each - 1), end='')
# SYC{1_h0pe_yOu_ChAse_YoUr_dr3ams} 我Chase你的梦!
浪漫至死不渝 | JS逆向
源码对变量名进行了混淆 去除混淆并对网页元素进行删去 得到主要逻辑
let k={
a:0,b:1,c:2,d:3,e:4,f:5,g:6,h:7,i:8,j:9,k:10,l:11,m:12,n:13,o:14,p:15,q:16,r:17,s:18,t:19,u:20,v:21,w:22,x:23,y:24,z:25,
A:0,B:1,C:2,D:3,E:4,F:5,G:6,H:7,I:8,J:9,K:10,L:11,M:12,N:13,O:14,P:15,Q:16,R:17,S:18,T:19,U:20,V:21,W:22,X:23,Y:24,Z:25
}
let a=[
{name:"A",yin:7, str:,
{name:"B" ,yin:24, str:,
{name:"C" ,yin:1, str:,
{name:"D" ,yin:4, str:,
{name:"E" ,yin:5, str:,
{name:"F" ,yin:2, str:,
{name:"G" ,yin:6, str:,
{name:"H" ,yin:5, str:,
{name:"I" ,yin:8, str:,
{name:"J" ,yin:3, str:,
{name:"K" ,yin:9, str:,
{name:"L" ,yin:8, str:,
{name:"M" ,yin:11, str:,
{name:"N" ,yin:3, str:,
{name:"O" ,yin:7, str:,
{name:"P" ,yin:14, str:,
{name:"Q" ,yin:15, str:,
{name:"R" ,yin:16, str:,
{name:"S" ,yin:17, str:,
{name:"T" ,yin:18, str:,
{name:"U" ,yin:8, str:,
{name:"V" ,yin:20, str:,
{name:"W" ,yin:3, str:,
{name:"X" ,yin:2, str:,
{name:"Y" ,yin:23, str:,
{name:"Z" ,yin:24, str:
];
let target_2=0;
let key = new Array(125, 130, 131, 122, 117, 110, 123, 125, 130, 131, 122, 117, 110, 123, 99, 99, 99, 99);
let s = "";
let target = false;
function fl(e)
{
if(clickb==true)
{
const num_of_fence = 3;
const fence_key = '53X211WH04N';
const Text1 = decryptRailFence(fence_key, num_of_fence); //Text1 = '510321H4XWN'
let key = e.key;
if((key<='z'&&key>='a')||(key<='Z'&&key>='A'))
{
let p=a[k[key]];
s += p.name;
const intArr = [];
for (let i = 0; i < s.length; i++)
{
const charCode = s.charCodeAt(i);
intArr.push(charCode); //intArr记录s中每个字符对应的ASCII值
}
if (s.length % 18 == 0)
{
let len = s.length / 18;
for (let i = 0; i < len; i++)
{
for (let control = 0; control < 18; control++)
{
if (control < 14)
{
intArr[i + control] ^= Text1.charCodeAt(control % 7);
intArr[i + control] += 10;
}
else
{
intArr[i+ control] ^= Text1.charCodeAt(control -7);
intArr[i + control] += 99;
}
}
}
for (let i = 0; i < s.length; i++)
{
let cnt = 0;
if (intArr[i] == key[0])
{
for (let control = 0; control < key.length && i+ control < intArr.length; control++)
{
if (intArr[i + control] == key[control])
{
cnt++;
}
}
}
if (cnt >= 18) {
target = true;
break;
}
}
}
if(target&&target_2==0)
{
print "ok"
}
}
}
主要是先用栅栏密码对key进行加密 然后对输入逐位字符进行加密 写出解密脚本
key = [125, 130, 131, 122, 117, 110, 123, 125, 130, 131, 122, 117, 110, 123, 99, 99, 99, 99]
Text1 = '5201314WXHN'
for i in range(18):
if i < 14:
print(chr((key[i] - 10) ^ ord(Text1[i % 7])), end='')
else:
print(chr((key[i] - 99) ^ ord(Text1[i - 7])), end='')
# FJIAXUEFJIAXUEWXHN
寻找初音未来 | Go语言逆向 | 一坨go史
go语言所有的字符串在内存上都是连续的 所以对一个字符串对应的长度和偏移量非常重要
附件放到虚拟机中打开 发现提示输入初音未来色 上网搜索知道是39C5BB 用IDA打开 发现这个输入通过某些加密算法得到key
再用该key进行RC4加密直接动态调试得到key为CCCCCCCCCCCCCCCCCC 用python内置的RC4解密算法进行解密
from Crypto.Cipher import ARC4
ciphertext = b'\x25\x6F\x3D\x6C\xF9\xE0\xCF\x3F\x2E\x24\xC6\x7B\x81\xBF\x55\x4F\x0D\x99\x87\x47\x48\xF7\xB9\x98\xFB\x1B\x22\xEC\x84\x23\xFD\xB2'
key = b'CCCCCCCCCCCCCCCCCC'
cipher = ARC4.new(key)
plaintext = cipher.decrypt(ciphertext=ciphertext)
print(plaintext)
# b'SYC{N0thing_1s_sEriOus_But_MIku}'
AES! AES? | AES算法魔改
Exinfo查到无壳 64位win程序 IDA64打开 伪代码中看到核心加密逻辑是Shiftrow()和transform()伪代码如下
void __fastcall ShiftRow(__int64 flag)
{
int v1; // [rsp+0h] [rbp-10h]
int j; // [rsp+4h] [rbp-Ch]
int i; // [rsp+8h] [rbp-8h]
int k; // [rsp+Ch] [rbp-4h]
for ( i = 0; i <= 15; i += 4 )
{
for ( j = 0; j < i / 4; ++j )
{
v1 = *(4i64 * i + flag);
for ( k = 0; k <= 2; ++k )
*(4i64 * (i + k) + flag) = *(flag + 4 * (i + k + 1i64));
*(4i64 * (i + k) + flag) = v1;
}
}
}
__int64 __fastcall tansform(__int64 flag)
{
__int64 result; // rax
unsigned __int8 v2; // dl
int v3; // eax
_DWORD *v4; // rcx
int v5[20]; // [rsp+0h] [rbp-60h]
int k; // [rsp+50h] [rbp-10h]
int j; // [rsp+54h] [rbp-Ch]
int i; // [rsp+58h] [rbp-8h]
int v9; // [rsp+5Ch] [rbp-4h]
v9 = 0;
for ( i = 0; i <= 15; ++i )
{
result = i;
v5[i] = *(4i64 * i + flag);
}
for ( j = 0; j <= 3; ++j )
{
for ( k = 0; k <= 3; ++k )
{
*(flag + 4i64 * v9) = v5[4 * k + j];
v2 = S[*(4i64 * v9 + flag)];
v3 = v9++;
v4 = (flag + 4i64 * v3);
result = v2;
*v4 = v2;
}
}
return result;
}
// 整体代码如下 其中还有一个异或加密 用来实现AES算法
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Str[48]; // [rsp+20h] [rbp-60h] BYREF
int flag1[16]; // [rsp+50h] [rbp-30h] BYREF
_BYTE flag2[96]; // [rsp+90h] [rbp+10h] BYREF
char v7[8]; // [rsp+F0h] [rbp+70h] BYREF
__int64 v8; // [rsp+F8h] [rbp+78h]
int v9; // [rsp+100h] [rbp+80h]
char v10[20]; // [rsp+110h] [rbp+90h] BYREF
char v11[15]; // [rsp+124h] [rbp+A4h] BYREF
char v12[13]; // [rsp+133h] [rbp+B3h] BYREF
__int64 v13[3]; // [rsp+140h] [rbp+C0h] BYREF
int v14; // [rsp+158h] [rbp+D8h]
__int16 v15; // [rsp+15Ch] [rbp+DCh]
char v16[16]; // [rsp+160h] [rbp+E0h] BYREF
int v17[40]; // [rsp+170h] [rbp+F0h] BYREF
char v18[176]; // [rsp+210h] [rbp+190h] BYREF
__int16 v19; // [rsp+2C0h] [rbp+240h]
char v20; // [rsp+2C2h] [rbp+242h]
int v21; // [rsp+2C4h] [rbp+244h]
int _32; // [rsp+2C8h] [rbp+248h]
int i2; // [rsp+2CCh] [rbp+24Ch]
int cnt; // [rsp+2D0h] [rbp+250h]
int i1; // [rsp+2D4h] [rbp+254h]
int nn; // [rsp+2D8h] [rbp+258h]
int mm; // [rsp+2DCh] [rbp+25Ch]
int jj; // [rsp+2E0h] [rbp+260h]
int kk; // [rsp+2E4h] [rbp+264h]
int ii; // [rsp+2E8h] [rbp+268h]
int n; // [rsp+2ECh] [rbp+26Ch]
int m; // [rsp+2F0h] [rbp+270h]
int k; // [rsp+2F4h] [rbp+274h]
int j; // [rsp+2F8h] [rbp+278h]
int i; // [rsp+2FCh] [rbp+27Ch]
(_main)(argc, argv, envp);
memset(v18, 0, sizeof(v18));
v19 = 0;
v20 = 0;
memset(v17, 0, sizeof(v17));
v17[0] = 0xE0;
v17[1] = 0xFFFFFF05;
v17[2] = 0xFFFFFF6E;
v17[3] = 0xFFFFFFC2;
v17[4] = 0xFFFFFF6E;
v17[5] = 0xFFFFFF99;
v17[6] = 0xFFFFFF68;
v17[7] = 0x45;
v17[8] = 0xFFFFFF7D;
v17[9] = 0xFFFFFF1F;
v17[10] = 0xFFFFFF3F;
v17[11] = 0xFFFFFFF9;
v17[12] = 0xFFFFFF97;
v17[13] = 0xFFFFFF76;
v17[14] = 0x3B;
v17[15] = 0x92;
v17[16] = 0x2F;
v17[17] = 0xFFFFFF44;
v17[18] = 0xFFFFFF06;
v17[19] = 0xFFFFFF67;
v17[20] = 0xFFFFFFA8;
v17[21] = 0xFFFFFFEB;
v17[22] = 0xFFFFFFEC;
v17[23] = 0x4A;
v17[24] = 0xFFFFFF6F;
v17[25] = 0xFFFFFFE8;
v17[26] = 0xFFFFFF35;
v17[27] = 0xFFFFFFF9;
v17[28] = 0xFFFFFFAC;
v17[29] = 0xFFFFFFA7;
v17[30] = 0x8C;
v17[31] = 0x71;
qmemcpy(v16, "nyi", 3);
v16[3] = -125;
v16[4] = 121;
v16[5] = 127;
v16[6] = 105;
v16[7] = 117;
v16[8] = 121;
v16[9] = 120;
v16[10] = -127;
v16[11] = 105;
v16[12] = 93;
v16[13] = 99;
v16[14] = 77;
v16[15] = 73;
v13[0] = 0x78732A6F6D6B767Ai64;
v13[1] = 0x7C7F79832A7E7F79i64;
v13[2] = 0x142A44716B76702Ai64;
v14 = 0;
v15 = 0;
v10[0] = -125;
v10[1] = 111;
v10[2] = 125;
v10[3] = 43;
v10[4] = 42;
v10[5] = -125;
v10[6] = 121;
v10[7] = 127;
v10[8] = 42;
v10[9] = 107;
v10[10] = 124;
v10[11] = 111;
v10[12] = 42;
v10[13] = 124;
v10[14] = 115;
v10[15] = 113;
v10[16] = 114;
v10[17] = 126;
v10[18] = 43;
v10[19] = 20;
qmemcpy(v11, "\nxy", 3);
v11[3] = -120;
v11[4] = 126;
v11[5] = 124;
v11[6] = -125;
v11[7] = 42;
v11[8] = 107;
v11[9] = 113;
v11[10] = 107;
v11[11] = 115;
v11[12] = 120;
v11[13] = -120;
v11[14] = 20;
qmemcpy(v12, "\nxy", 3);
v12[3] = -120;
v12[4] = 10;
for ( i = 0; i <= 23; ++i )
*(v13 + i) -= 10;
for ( j = 0; j <= 39; ++j )
v10[j] -= 10;
*v7 = 0i64;
v8 = 0i64;
v9 = 0;
printf("%s", v13);
scanf("%s", Str);
_32 = strlen(Str);
v21 = strlen(v7);
if ( _32 != 32 )
{
printf("%s", &v12[1]);
exit(0);
}
for ( k = 0; k <= 15; ++k )
{
v16[k] -= 10;
v7[k] = v16[k];
}
if ( Str[5] != '.' || Str[10] != 'l' || Str[17] != '0' )
{
printf("%s", &v12[1]);
exit(0);
}
for ( m = 0; m <= 15; ++m )
v18[m] = v7[m]; // v18 = do_you_konw_SYC?
for ( n = 1; n <= 10; ++n )
{
for ( ii = 0; ii <= 31; ++ii )
v18[16 * n + ii] = v18[16 * n - 16 + ii] ^ S[v18[16 * n - 16 + ii]];
}
HIBYTE(v19) = '9';
kk = 0;
for ( jj = 0; jj < _32; ++jj )
flag1[jj] = S[Str[jj]];
for ( kk = 0; kk <= 0; ++kk )
{
ShiftRow(flag1); // 将第n行的前(n - 1)个元素向右移动(5 - n)格
ShiftRow(flag2);
tansform(flag1);
tansform(flag2);
for ( mm = 0; mm <= 15; ++mm )
{
flag1[mm] ^= v18[16 * kk + mm]; // 将flag与key1异或
flag1[mm + 16] ^= v18[16 * kk + mm];
}
for ( nn = 0; nn < _32; ++nn )
flag1[nn] = S[flag1[nn]]; // 将flag中的值替换为S中以flag的值为索引的值
}
ShiftRow(flag1);
ShiftRow(flag2);
for ( i1 = 0; i1 <= 15; ++i1 ) // 将flag与key2异或
{
flag1[i1] ^= v18[16 * kk + i1];
flag1[i1 + 16] ^= v18[16 * kk + i1];
}
cnt = 0;
for ( i2 = 0; i2 <= 31; ++i2 )
{
if ( flag1[i2] == v17[i2] )
++cnt;
}
if ( cnt <= 31 )
printf("%s", &v11[1]);
else
printf("%s", v10);
return 0;
}
据此写出解密脚本
S = [0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01,
0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D,
0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4,
0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7,
0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2,
0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E,
0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB,
0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB,
0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C,
0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C,
0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D,
0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A,
0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3,
0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A,
0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E,
0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9,
0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9,
0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99,
0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]
key_ = "do_you_konw_SYC?"
v17 = [None] * 32
v17[0] = 0xE0
v17[1] = 0x05
v17[2] = 0x6E
v17[3] = 0xC2
v17[4] = 0x6E
v17[5] = 0x99
v17[6] = 0x68
v17[7] = 0x45
v17[8] = 0x7D
v17[9] = 0x1F
v17[10] = 0x3F
v17[11] = 0xF9
v17[12] = 0x97
v17[13] = 0x76
v17[14] = 0x3B
v17[15] = 0x92
v17[16] = 0x2F
v17[17] = 0x44
v17[18] = 0x06
v17[19] = 0x67
v17[20] = 0xA8
v17[21] = 0xEB
v17[22] = 0xEC
v17[23] = 0x4A
v17[24] = 0x6F
v17[25] = 0xE8
v17[26] = 0x35
v17[27] = 0xF9
v17[28] = 0xAC
v17[29] = 0xA7
v17[30] = 0x8C
v17[31] = 0x71
def shift_row(flag:list) -> list:
for i in range(0, 4):
for _ in range(i):
for k in range(3):
flag[4 * i + 3 - k], flag[4 * i + 3 - k - 1] = flag[4 * i + 3 - k - 1], flag[4 * i + 3 - k]
return flag
key1 = []
for each in key_:
key1.append(ord(each) & 0xFF)
key2 = []
for i in range(16):
key2.append(key1[i] ^ S[key1[i]] & 0xFF)
flag_after = []
for i in range(32):
temp = v17[i] ^ key2[i % 0x10]
flag_after.append(temp)
flag = shift_row(flag_after[0 :16])
flag += shift_row(flag_after[16:32])
for i in range(32):
flag[i] = S.index(flag[i])
flag[i] ^= key1[i % 0x10]
flag1 = [None] * 16
flag2 = [None] * 16
cnt = 0
for i in range(4):
for j in range(4):
flag1[4 * j + i] = S.index(flag[cnt])
cnt += 1
for i in range(4):
for j in range(4):
flag2[4 * j + i] = S.index(flag[cnt])
cnt += 1
flag_last = shift_row(flag1)
flag_last += shift_row(flag2)
for each in flag_last:
t = S.index(each)
try:
print(chr(t), end='')
except:
pass
# SYC{0.o_Thls_1s_n0t_A3s_(q^_^p)}
另外 不要手抄key不要手抄key不要手抄key不要手抄key不要手抄key不要手抄key不要手抄key不要手抄key不要手抄key不要手抄key
ezandroid | 安卓逆向
apk用jeb打开 有两个主要活动如下
package com.example.babyapk_1;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View.OnClickListener;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import b.f;
public class MainActivity extends f {
public class b {
public int[] a;
public b() {
this.a = new int[]{2023708229, -158607964, 0x81963FFA, 0x458FAC58};
}
}
public EditText o;
@Override // b.f
public void onCreate(Bundle bundle0) {
new Handler();
super.onCreate(bundle0);
this.setContentView(0x7F0B001C); // layout:activity_main
Button button0 = (Button)this.findViewById(0x7F080057); // id:button
this.o = (EditText)this.findViewById(0x7F080097); // id:edit_text
button0.setOnClickListener(new View.OnClickListener() {
@Override // android.view.View$OnClickListener
public void onClick(View view0) {
String s = MainActivity.this.o.getText().toString();
if(s.length() > 24) {
MainActivity.this.o.setText("");
s = MainActivity.this.o.getText().toString();
}
if(((s.length() == 0 ? 1 : 0) | (s.length() % 24 == 0 ? 0 : 1)) != 0) {
int v = 24 - s.length() % 24;
StringBuilder stringBuilder0 = new StringBuilder(s);
for(int v1 = 0; v1 < v; ++v1) {
stringBuilder0.append('X');
}
s = stringBuilder0.toString();
}
StringBuilder stringBuilder1 = new StringBuilder();
StringBuilder stringBuilder2 = new StringBuilder();
for(int v2 = 0; v2 < s.length(); ++v2) {
if(v2 % 2 == 0) {
stringBuilder1.append(s.charAt(v2));
}
else {
stringBuilder2.append(s.charAt(v2));
}
}
b mainActivity$b0 = new b(MainActivity.this);
String s1 = stringBuilder2.toString();
byte[] arr_b = stringBuilder1.toString().getBytes();
int v3 = arr_b.length >> 2;
int[] arr_v = new int[v3];
int v5 = 0;
for(int v4 = 0; v4 < arr_b.length; v4 += 4) {
int v6 = arr_b[v4 + 3];
if(v6 < 0) {
v6 += 0x100;
}
int v7 = arr_b[v4 + 2];
if(v7 < 0) {
v7 += 0x100;
}
int v8 = arr_b[v4 + 1];
if(v8 < 0) {
v8 += 0x100;
}
arr_v[v5] = v6 | v7 << 8 | v8 << 16 | arr_b[v4] << 24;
++v5;
}
int v9 = arr_v[0];
int v10 = arr_v[1];
int v11 = arr_v[2];
int[] arr_v1 = mainActivity$b0.a;
int key_0 = arr_v1[0];
int key_1 = arr_v1[1];
int key_2 = arr_v1[2];
int key_3 = arr_v1[3];
int v16 = 0;
for(int v17 = 0; v17 < 0x20; ++v17) {
v16 += -1640531527;
v9 += (v10 << 4) + key_0 ^ v10 + v16 ^ (v10 >> 5) + key_1;
v10 += (v9 << 4) + key_2 ^ v9 + v16 ^ (v9 >> 5) + key_3;
}
arr_v[0] = v9;
for(int v18 = 0; v18 < 0x20; ++v18) {
v16 += -1640531527;
v11 += (v10 << 4) + key_0 ^ v10 + v16 ^ (v10 >> 5) + key_1;
v10 += (v11 << 4) + key_2 ^ v11 + v16 ^ (v11 >> 5) + key_3;
}
arr_v[1] = v11;
arr_v[2] = v10;
byte[] arr_b1 = new byte[v3 << 2];
int v20 = 0;
for(int v19 = 0; v19 < v3; ++v19) {
arr_b1[v20 + 3] = (byte)(arr_v[v19] & 0xFF);
arr_b1[v20 + 2] = (byte)(arr_v[v19] >> 8 & 0xFF);
arr_b1[v20 + 1] = (byte)(arr_v[v19] >> 16 & 0xFF);
arr_b1[v20] = (byte)(arr_v[v19] >> 24 & 0xFF);
v20 += 4;
}
for(int v21 = 0; v21 < new byte[]{-91, -8, -110, -55, -49, 75, 0x73, 13, -76, (byte)0x8F, 102, 80}.length; ++v21) {
System.out.println(((int)arr_b1[v21]));
}
int v23 = 1;
for(int v22 = 0; true; ++v22) {
byte[] arr_b2 = new byte[]{-91, -8, -110, -55, -49, 75, 0x73, 13, -76, (byte)0x8F, 102, 80};
if(v22 >= arr_b2.length) {
break;
}
if(arr_b1[v22] != arr_b2[v22]) {
Toast.makeText(MainActivity.this, "You\'re Wrong!\n", 0).show();
v23 = 0;
}
}
Intent intent0 = new Intent(MainActivity.this, MainActivity2.class);
intent0.putExtra("ad@#E!@a123", s1);
intent0.putExtra("eCAS213@!@3", arr_b1);
if(v23 == 1) {
MainActivity.this.startActivity(intent0);
}
}
});
}
}
package com.example.babyapk_1;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import b.f;
public class MainActivity2 extends f {
@Override // b.f
public void onCreate(Bundle bundle0) {
super.onCreate(bundle0);
this.setContentView(0x7F0B001D); // layout:activity_main2
Intent intent0 = this.getIntent();
byte[] arr_b = intent0.getStringExtra("ad@#E!@a123").getBytes();
byte[] arr_b1 = intent0.getByteArrayExtra("eCAS213@!@3");
int v1 = 1;
for(int v = 0; v < arr_b1.length; ++v) {
arr_b1[v] = (byte)(arr_b1[v] ^ arr_b[v % arr_b.length]);
if(arr_b1[v] != new int[]{-107, -106, 0xFFFFFFA1, 0xFFFFFF8D, 0xFFFFFF89, 0x7F, 26, 0x79, -62, -20, 86, 9}[v]) {
Toast.makeText(this, "N0T Right,Maybe try more harder?\n", 0).show();
v1 = 0;
}
}
if(v1 == 1) {
Toast.makeText(this, "Congratulations!", 1).show();
}
}
}
当MainActivity1中的匹配通过后才会进行MainActivity2的另一部分加密 主要是分奇偶索引进行TEA或异或加密 据此写出解密脚本
#include<stdio.h>
int main(){
unsigned char arr_even[12] = {-107, -106, 0xFFFFFFA1, 0xFFFFFF8D, 0xFFFFFF89, 0x7F, 26, 0x79, -62, -20, 86, 9};
unsigned char key_even[12] = {-91, -8, -110, -55, -49, 75, 0x73, 13, -76, 0x8F, 102, 80};
char flag_even[12];
for(int i = 0; i < 12; i++){
flag_even[i] = arr_even[i] ^ key_even[i];
}
int flag_odd_[3];
for(int i = 0; i < 12; i += 4){
flag_odd_[(int)(i / 4)] = key_even[i + 3] | key_even[i + 2] << 8 | key_even[i + 1] << 16 | key_even[i] << 24;
}
int TEA_key[4] = {2023708229, -158607964, 0x81963FFA, 0x458FAC58};
int delta = -1640531527 * 0x40;
for(int i = 0; i < 0x20; i++){
flag_odd_[2] -= (flag_odd_[1] << 4) + TEA_key[2] ^ flag_odd_[1] + delta ^ (flag_odd_[1] >> 5) + TEA_key[3];
flag_odd_[1] -= (flag_odd_[2] << 4) + TEA_key[0] ^ flag_odd_[2] + delta ^ (flag_odd_[2] >> 5) + TEA_key[1];
delta += 1640531527;
}
for(int i = 0; i < 0x20; i++){
flag_odd_[2] -= (flag_odd_[0] << 4) + TEA_key[2] ^ flag_odd_[0] + delta ^ (flag_odd_[0] >> 5) + TEA_key[3];
flag_odd_[0] -= (flag_odd_[2] << 4) + TEA_key[0] ^ flag_odd_[2] + delta ^ (flag_odd_[2] >> 5) + TEA_key[1];
delta += 1640531527;
}
unsigned char flag_odd[12];
for(int i = 3; i >= 0; i--){
flag_odd[3 - i] = (flag_odd_[0] >> i * 8);
}
for(int i = 3; i >= 0; i--){
flag_odd[7 - i] = (flag_odd_[2] >> i * 8);
}
for(int i = 3; i >= 0; i--){
flag_odd[11 - i] = (flag_odd_[1] >> i * 8);
}
printf("SYC{");
for(int i = 0; i < 24; i++){
if(i % 2 == 0){
printf("%c", flag_odd[(int)(i / 2)]);
}
else{
printf("%c", flag_even[(int)(i / 2)]);
}
}
printf("}");
// SYC{T00nV3tD3F34Tint0vict0rY}
return 0;
}
是男人就来扎针 | Unity引擎游戏逆向
Unity引擎游戏的控制逻辑一般存放在.\*_Data\Managed\Assembly-CSharp.dll中 用dnspy打开 主要逻辑如下
using System;
using System.Collections;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
// Token: 0x02000002 RID: 2
public class GameManager : MonoBehaviour
{
// Token: 0x06000002 RID: 2 RVA: 0x000020A9 File Offset: 0x000004A9
public static string RemoveDash(string str)
{
str = str.Replace("-", string.Empty);
return str;
}
// Token: 0x06000003 RID: 3 RVA: 0x000020C0 File Offset: 0x000004C0
public static string what(string str)
{
MD5 md = MD5.Create();
byte[] bytes = Encoding.Default.GetBytes(str);
byte[] value = md.ComputeHash(bytes);
return GameManager.RemoveDash(BitConverter.ToString(value));
}
// Token: 0x06000004 RID: 4 RVA: 0x000020F4 File Offset: 0x000004F4
private void Start()
{
this.startPoint = GameObject.Find("StartPoint").transform;
this.spawnPoint = GameObject.Find("SpawnPoint").transform;
this.mainCamera = Camera.main;
this.SpawnPin();
}
// Token: 0x06000005 RID: 5 RVA: 0x00002134 File Offset: 0x00000534
private void Update()
{
if (this.score == 30)
{
string text = string.Empty;
for (int i = 0; i < this.magicc.Length; i++)
{
char c = (char)this.magicc[i];
text += c;
}
this.flagText.text = text;
this.nothing += GameManager.what(this.flagText.text);
this.nothing += '\0';
}
if (this.score == 40)
{
string text2 = string.Empty;
for (int j = 0; j < this.magic.Length; j++)
{
char c2 = (char)this.magic[j];
text2 += c2;
}
this.flagText.text = text2;
text2 += '\0';
}
if (this.score == 100)
{
this.scoreText.text = "!";
this.flagText.text = this.nothing;
}
if (this.isGameOver)
{
return;
}
if (Input.GetMouseButtonDown(0))
{
this.score++;
this.scoreText.text = this.score.ToString();
this.currentPin.StartFly();
this.SpawnPin();
for (int k = 0; k < this.magicc.Length; k++)
{
this.magicc[k] ^= this.score;
this.magic[k] ^= this.score;
}
}
}
// Token: 0x06000006 RID: 6 RVA: 0x000022F6 File Offset: 0x000006F6
private void SpawnPin()
{
this.currentPin = UnityEngine.Object.Instantiate<GameObject>(this.pinPrefab, this.spawnPoint.position, this.pinPrefab.transform.rotation).GetComponent<Pin>();
}
// Token: 0x06000007 RID: 7 RVA: 0x00002329 File Offset: 0x00000729
public void GameOver()
{
if (this.isGameOver)
{
return;
}
GameObject.Find("Circle").GetComponent<RotateSelf>().enabled = false;
base.StartCoroutine(this.GameOverAnimation());
this.isGameOver = true;
}
// Token: 0x06000008 RID: 8 RVA: 0x00002360 File Offset: 0x00000760
private IEnumerator GameOverAnimation()
{
for (;;)
{
this.mainCamera.backgroundColor = Color.Lerp(this.mainCamera.backgroundColor, Color.red, this.speed * Time.deltaTime);
this.mainCamera.orthographicSize = Mathf.Lerp(this.mainCamera.orthographicSize, 4f, this.speed * Time.deltaTime);
if (Mathf.Abs(this.mainCamera.orthographicSize - 4f) < 0.01f)
{
break;
}
yield return 0;
}
yield return new WaitForSeconds(0.2f);
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
yield break;
}
// Token: 0x04000001 RID: 1
private Transform startPoint;
// Token: 0x04000002 RID: 2
private Transform spawnPoint;
// Token: 0x04000003 RID: 3
private Pin currentPin;
// Token: 0x04000004 RID: 4
private bool isGameOver;
// Token: 0x04000005 RID: 5
private int score;
// Token: 0x04000006 RID: 6
private Camera mainCamera;
// Token: 0x04000007 RID: 7
private string nothing = string.Empty;
// Token: 0x04000008 RID: 8
private int[] magicc = new int[]
{
75,
109,
102,
63,
107,
112,
63,
108,
124,
112,
109,
122,
63,
43,
47,
63,
111,
112,
118,
113,
107,
108,
62
};
// Token: 0x04000009 RID: 9
private int[] magic = new int[]
{
124,
90,
81,
8,
92,
71,
8,
90,
77,
73,
75,
64,
8,
25,
24,
24,
8,
88,
71,
65,
70,
92,
91,
9
};
// Token: 0x0400000A RID: 10
public Text scoreText;
// Token: 0x0400000B RID: 11
public Text flagText;
// Token: 0x0400000C RID: 12
public GameObject pinPrefab;
// Token: 0x0400000D RID: 13
public float speed = 3f;
}
可以看到游戏前30次每刷新一次分数就会与明文进行异或 最后进行md5加密然后在分数达到100时显示 显然不可能点到100 但是可以先点到30 再用CE改到100 写出解密脚本
import hashlib
key = [ 75, 109, 102, 63, 107, 112, 63, 108, 124, 112, 109, 122, 63, 43, 47, 63, 111, 112, 118, 113, 107, 108, 62]
convt = hashlib.md5()
for i in range(1, 31):
for j in range(len(key)):
key[j] ^= i
flag = ''
for each in key:
flag += chr(each)
convt.update(flag.encode())
print(convt.hexdigest().upper())
# CBDDD133B60130856D3C695D9E5ED6A5
babycode | 不知道什么加密
IDA64打开 伪代码如下 其中两个简单加密算法不展示
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int v3; // eax
int v5; // [rsp+4h] [rbp-13Ch]
int i; // [rsp+8h] [rbp-138h]
int j; // [rsp+Ch] [rbp-134h]
int k; // [rsp+10h] [rbp-130h]
char enc[4]; // [rsp+20h] [rbp-120h] BYREF
int v10[33]; // [rsp+24h] [rbp-11Ch]
char input[113]; // [rsp+B7h] [rbp-89h] BYREF
unsigned __int64 v12; // [rsp+128h] [rbp-18h]
v12 = __readfsqword(0x28u);
v5 = 1;
puts("please input your flag:");
__isoc99_scanf("%s", &input[9]);
*enc = 120;
v10[0] = 91;
v10[1] = 86;
v10[2] = 122;
v10[3] = 93;
v10[4] = 84;
v10[5] = 37;
v10[6] = 49;
v10[7] = 32;
v10[8] = 104;
v10[9] = 61;
v10[10] = 100;
v10[11] = -110;
v10[12] = 118;
v10[13] = 99;
v10[14] = 123;
v10[15] = 89;
v10[16] = 87;
v10[17] = 33;
v10[18] = -124;
v10[19] = 87;
v10[20] = 118;
v10[21] = -121;
v10[22] = 114;
v10[23] = -124;
v10[24] = -123;
v10[25] = 112;
v10[26] = -98;
v10[27] = 79;
v10[28] = 112;
v10[29] = 114;
v10[30] = -124;
v10[31] = 87;
v10[32] = -120;
strcpy(input, "fuwafuwa");
for ( i = 0; i < strlen(&input[9]); ++i )
input[i + 9] = (16 * input[i + 9]) | (input[i + 9] >> 4) & 0xF;// 互换输入中的高/低四位
encode(&input[9]);
for ( j = 0; j < strlen(&input[9]); ++j )
{
input[j + 9] += j;
input[j + 9] ^= input[j % 8] % 32 + 1;
ceasar(input, j); // 向后移j位的凯撒加密
v3 = strlen(input);
reverse(input, v3); // 对称对换key(0->8, 1->7...
}
for ( k = 0; k <= strlen(enc); ++k )
{
if ( input[k + 9] != *&enc[4 * k] )
{
v5 = 0;
puts("no way!");
break;
}
}
if ( v5 == 1 )
puts("your input is flag!");
return 0LL;
}
char *__fastcall encode(const char *input)
{
unsigned __int8 v2; // [rsp+17h] [rbp-49h]
int i; // [rsp+18h] [rbp-48h]
int v4; // [rsp+1Ch] [rbp-44h]
char *ptr_input; // [rsp+20h] [rbp-40h]
char *key2; // [rsp+28h] [rbp-38h]
char *ptr_input_; // [rsp+30h] [rbp-30h]
unsigned __int64 j; // [rsp+38h] [rbp-28h]
size_t len_of_input; // [rsp+40h] [rbp-20h]
__int64 max_key; // [rsp+48h] [rbp-18h]
char *v11; // [rsp+50h] [rbp-10h]
unsigned __int64 last; // [rsp+58h] [rbp-8h]
len_of_input = strlen(input);
max_key = 3 * ((len_of_input >> 1) + 1);
v11 = malloc(max_key + len_of_input);
key2 = &v11[max_key]; // 输入的首地址
last = &v11[max_key - 1 + len_of_input]; // v11的最后一个元素
ptr_input = &v11[max_key];
memcpy(&v11[max_key], input, len_of_input); // 最后的一段元素和输入相同
while ( ptr_input <= last )
{
if ( *ptr_input )
{
v2 = 0;
for ( ptr_input_ = ptr_input; ptr_input_ <= last; ++ptr_input_ )
{
v4 = v2 << 8;
v2 = *ptr_input_ & 0x3F;
*ptr_input_ = (*ptr_input_ + v4) >> 6;
}
*--key2 = off_55B72E249018[v2];
}
else
{
++ptr_input;
}
}
for ( i = 0; i <= 19; ++i )
key += rand() % 100;
key = key % 0x20 + 1;
for ( j = 0LL; j < &v11[max_key] - key2; ++j )
input[j] = key ^ key2[j];
input[j] = 0;
return v11;
}
核心加密是一个base64的换表 要注意的是其中的key动态调试出来并不正确 因为程序会检测动态调试改变key的初值
.init_array:000055B72E248D80 _init_array segment qword public 'DATA' use64
.init_array:000055B72E248D80 assume cs:_init_array
.init_array:000055B72E248D80 ;org 55B72E248D80h
.init_array:000055B72E248D80 00 62 24 2E B7 55 00 00 dq offset sub_55B72E246200
.init_array:000055B72E248D88 09 62 24 2E B7 55 00 00 dq offset sub_55B72E246209
.init_array:000055B72E248D88 _init_array ends
...
...
.text:000055B72E246209 sub_55B72E246209 proc near ; DATA XREF: .init_array:000055B72E248D88↓o
.text:000055B72E246209
.text:000055B72E246209 var_4= dword ptr -4
.text:000055B72E246209
.text:000055B72E246209 ; __unwind {
.text:000055B72E246209 F3 0F 1E FA endbr64
.text:000055B72E24620D 55 push rbp
.text:000055B72E24620E 48 89 E5 mov rbp, rsp
.text:000055B72E246211 C7 45 FC 00 00 00 00 mov [rbp+var_4], 0
.text:000055B72E246218 BB 00 00 00 00 mov ebx, 0 ; ptrace_request
.text:000055B72E24621D B9 00 00 00 00 mov ecx, 0 ; pid
.text:000055B72E246222 BA 00 00 00 00 mov edx, 0 ; addr
.text:000055B72E246227 B8 1A 00 00 00 mov eax, 1Ah
.text:000055B72E24622C CD 80 int 80h ; LINUX - sys_ptrace
.text:000055B72E24622C
.text:000055B72E24622E 89 45 FC mov [rbp+var_4], eax
.text:000055B72E246231 8B 45 FC mov eax, [rbp+var_4]
.text:000055B72E246234 48 98 cdqe
.text:000055B72E246236 48 83 F8 FF cmp rax, 0FFFFFFFFFFFFFFFFh
.text:000055B72E24623A 75 0A jnz short loc_55B72E246246
.text:000055B72E24623A
.text:000055B72E24623C C7 05 CA 2D 00 00 08 00 00 00 mov cs:key, 8
.text:000055B72E24623C
.text:000055B72E246246
.text:000055B72E246246 loc_55B72E246246: ; CODE XREF: sub_55B72E246209+31↑j
.text:000055B72E246246 90 nop
.text:000055B72E246247 5D pop rbp
.text:000055B72E246248 C3 retn
.text:000055B72E246248 ; } // starts at 55B72E246209
.text:000055B72E246248
.text:000055B72E246248 sub_55B72E246209 endp
所以用key在(1, 31)且加密后密文都在表中爆破出key为21 据此写出解密脚本
def emulator(key:list, time:int):
for i in range(8):
key[i] = 97 + (key[i] - 97 + time) % 26
def antiemulator(key:list, time:int):
for i in range(8):
key[i] = 97 + (key[i] - 97 - time) % 26
table = [ord(val) for val in 'i5jLW7S0GX6uf1cv3ny4q8es2Q+bdkYgKOIT/tAxUrFlVPzhmow9BHCMDpEaJRZN']
enc = [val & 0xFF for val in [120, 91, 86, 122, 93, 84, 37, 49, 32, 104, 61, 100, -110, 118, 99, 123, 89, 87, 33, -124, 87, 118, -121, 114, -124, -123, 112, -98, 79, 112, 114, -124, 87, -120]]
key_0 = 'fuwafuwa'
key = [ord(val) for val in key_0]
for i in range(34):
emulator(key, i)
key = key[::-1]
for i in range(33, -1, -1):
key = key[::-1]
antiemulator(key, i)
enc[i] ^= key[i % 8] % 32 + 1
enc[i] -= i
for i in range(34):
enc[i] ^= 21
enc = [table.index(val) for val in enc]
flag = ''
for each in enc:
flag += "{:06b}".format(each)
flag = flag[4:]
flag = [flag[8 * i:8 * i + 8] for i in range(len(enc))]
print("SYC{", end='')
for each in flag:
try:
print(chr(int(each[4:8] + each[0:4], 2)), end='')
except:
pass
print("}", end='')
# SYC{HbwKqCOAOVXdHAbG0HeinZkez}
yakvm | 虚拟机逆向
main为生成的虚拟机 IDA打开发现是无符号go 用go paraser恢复符号 搜索有关操作码的函数

发现有一个ShowOpcodes函数 但 调试时不进过该函数 交叉引用找到调用它的函数

在判断处下断点 调试时通过改ZF寄存器步进ShowOpcodes函数 得到可读操作码 根据官方文档分析如下
2:6->2:9 0:OP:type byte
2:4->2:119 1:OP:type slice
2:11->2:13 2:OP:push 137
2:15->2:17 3:OP:push 108
2:19->2:21 4:OP:push 159
2:23->2:25 5:OP:push 114
2:27->2:29 6:OP:push 185
2:31->2:32 7:OP:push 90
2:34->2:36 8:OP:push 174
2:38->2:39 9:OP:push 68
2:41->2:43 10:OP:push 160
2:45->2:46 11:OP:push 81
2:48->2:50 12:OP:push 179
2:52->2:53 13:OP:push 41
2:55->2:57 14:OP:push 186
2:59->2:60 15:OP:push 89
2:62->2:64 16:OP:push 168
2:66->2:67 17:OP:push 78
2:69->2:71 18:OP:push 229
2:73->2:75 19:OP:push 121
2:77->2:79 20:OP:push 149
2:81->2:83 21:OP:push 106
2:85->2:87 22:OP:push 147
2:89->2:91 23:OP:push 103
2:93->2:95 24:OP:push 156
2:97->2:99 25:OP:push 114
2:101->2:103 26:OP:push 133
2:105->2:106 27:OP:push 98
2:108->2:110 28:OP:push 146
2:112->2:114 29:OP:push 116
2:116->2:118 30:OP:push 181
2:4->2:119 31:OP:typedslice 29
2:4->2:119 32:OP:list 1
2:0->2:0 33:OP:pushleftr 1 arg_1 = key_list[29]
2:0->2:0 34:OP:list 1
2:0->2:119 35:OP:assign
3:0->3:4 36:OP:pushid print
3:6->3:25 37:OP:push please input flag:
3:5->3:26 38:OP:call vlen:1
3:0->3:26 39:OP:pop
4:4->4:6 40:OP:pushid get
4:7->4:8 41:OP:call vlen:0
4:4->4:8 42:OP:list 1
4:0->4:0 43:OP:pushleftr 2
4:0->4:0 44:OP:list 1 arg_2 = input[29]
4:0->4:8 45:OP:assign
5:18->8:0 46:OP:new-scope 2 {
5:3->5:5 47:OP:pushid len
5:7->5:7 48:OP:pushr 2
5:6->5:8 49:OP:call vlen:1 len(arg_2)
5:12->5:14 50:OP:pushid len
5:16->5:16 51:OP:pushr 1 len(arg_1)
5:15->5:17 52:OP:call vlen:1
5:3->5:17 53:OP:gt len(arg_1) > len(arg_2) -> goto globle63
5:18->8:0 54:OP:jmpf -> 63
5:18->8:0 55:OP:new-scope 3 {
6:1->6:7 56:OP:pushid println
6:9->6:32 57:OP:push input string too long! printf(too long!)
6:8->6:33 58:OP:call vlen:1
6:1->6:33 59:OP:pop
7:1->7:6 60:OP:return
5:18->8:0 61:OP:end-scope }
5:18->8:0 62:OP:jmp -> 63 globle63:
5:18->8:0 63:OP:end-scope }
12:8->21:0 64:OP:push function params[1] codes[54] (copy)
12:8->21:0 65:OP:list 1
12:0->12:4 66:OP:pushleftr 8 arg_8 = func1
12:0->12:4 67:OP:list 1
12:0->21:0 68:OP:assign
25:4->25:8 69:OP:pushr 8
25:10->25:10 70:OP:pushr 2
25:9->25:11 71:OP:call vlen:1 arg2 = func1(arg_2)
25:4->25:11 72:OP:list 1
25:0->25:0 73:OP:pushleftr 2
25:0->25:0 74:OP:list 1
25:0->25:11 75:OP:assign
28:9->33:0 76:OP:push function params[0] codes[40] (copy)
28:9->33:0 77:OP:list 1
28:0->28:4 78:OP:pushleftr 14
28:0->28:4 79:OP:list 1
28:0->33:0 80:OP:assign
36:0->36:4 81:OP:pushr 14
36:5->36:6 82:OP:call vlen:0 func2()
36:0->36:6 83:OP:pop
38:11->48:0 84:OP:push function params[0] codes[52] (copy)
38:11->48:0 85:OP:list 1
38:0->38:7 86:OP:pushleftr 19
38:0->38:7 87:OP:list 1
38:0->48:0 88:OP:assign
51:14->53:0 89:OP:new-scope 24
51:3->51:10 90:OP:pushr 19
51:11->51:12 91:OP:call vlen:0
51:14->53:0 92:OP:jmpf -> 100
51:14->53:0 93:OP:new-scope 25
52:1->52:5 94:OP:pushid print
52:7->52:24 95:OP:push yes! you get it!
52:6->52:25 96:OP:call vlen:1
52:1->52:25 97:OP:pop
51:14->53:0 98:OP:end-scope
51:14->53:0 99:OP:jmp -> 108
51:14->53:0 100:OP:end-scope
51:14->53:0 101:OP:new-scope 26
53:6->55:0 102:OP:new-scope 27
54:1->54:5 103:OP:pushid print
54:7->54:24 104:OP:push no this not flag
54:6->54:25 105:OP:call vlen:1
54:1->54:25 106:OP:pop
53:6->55:0 107:OP:end-scope
51:14->53:0 108:OP:end-scope
//func1 start
anonymous
13:1->19:1 1:OP:new-scope 6 {
13:1->19:1 2:OP:pushleftr 5 arg_5 = arg_3 = arg_2
13:18->13:18 3:OP:pushr 3
13:1->19:1 4:OP:fast-assign
13:1->19:1 5:OP:enter-for-range -> 47 for i in range(47)
13:1->19:1 6:OP:range-next
13:5->13:5 7:OP:pushleftr 6
13:8->13:8 8:OP:pushleftr 7
13:5->13:8 9:OP:list 2
13:1->19:1 10:OP:assign
13:20->19:1 11:OP:new-scope 7 {
14:16->16:2 12:OP:new-scope 8 {
14:5->14:5 13:OP:pushr 6
14:9->14:9 14:OP:push 2
14:5->14:9 15:OP:mod
14:14->14:14 16:OP:push 0
14:5->14:14 17:OP:eq arg_6 % 2 == 0 goto global31
14:16->16:2 18:OP:jmpf -> 31
14:16->16:2 19:OP:new-scope 9 else{
15:10->15:10 20:OP:pushr 7
15:14->15:17 21:OP:push 240
15:10->15:17 22:OP:xor
15:10->15:17 23:OP:list 1
15:3->15:3 24:OP:pushr 3
15:5->15:5 25:OP:pushr 6 arg_3[arg_6] = arg_7 ^ 240
15:3->15:6 26:OP:list 2
15:3->15:6 27:OP:list 1
15:3->15:17 28:OP:assign
14:16->16:2 29:OP:end-scope }
14:16->16:2 30:OP:jmp -> 44
14:16->16:2 31:OP:end-scope global31: }
14:16->16:2 32:OP:new-scope 10 {
16:9->18:2 33:OP:new-scope 11 {
17:10->17:10 34:OP:pushr 7 arg_7 ^ 15
17:14->17:17 35:OP:push 15
17:10->17:17 36:OP:xor
17:10->17:17 37:OP:list 1
17:3->17:3 38:OP:pushr 3
17:5->17:5 39:OP:pushr 6 arg_3[arg_6] = arg_7 ^ 15
17:3->17:6 40:OP:list 2
17:3->17:6 41:OP:list 1
17:3->17:17 42:OP:assign
16:9->18:2 43:OP:end-scope }
14:16->16:2 44:OP:end-scope }
13:20->19:1 45:OP:end-scope }
13:1->19:1 46:OP:exit-for-range -> 6
13:1->19:1 47:OP:pop
13:1->19:1 48:OP:end-scope }
20:8->20:8 49:OP:pushr 3
20:8->20:8 50:OP:list 1
20:1->20:8 51:OP:return
//func1 end
//func2 start
anonymous
28:15->33:0 0:OP:new-scope 13
29:1->32:1 1:OP:new-scope 14
29:1->32:1 2:OP:pushleftr 10
29:18->29:18 3:OP:pushr 2 arg_10 = arg_2
29:1->32:1 4:OP:fast-assign
29:1->32:1 5:OP:enter-for-range -> 36
29:1->32:1 6:OP:range-next
29:5->29:5 7:OP:pushleftr 11 arg_12 = arg_11 ?
29:8->29:8 8:OP:pushleftr 12
29:5->29:8 9:OP:list 2
29:1->32:1 10:OP:assign
29:20->32:1 11:OP:new-scope 15 {
30:6->30:6 12:OP:pushr 11 arg_13 = arg_11 * 2
30:10->30:10 13:OP:push 2
30:6->30:10 14:OP:mul
30:6->30:10 15:OP:list 1
30:2->30:2 16:OP:pushleftr 13
30:2->30:2 17:OP:list 1
30:2->30:10 18:OP:assign
31:11->31:11 19:OP:pushr 12 //用与或非实现异或
31:10->31:11 20:OP:not arg_12 ^ arg_13
31:15->31:15 21:OP:pushr 13
31:10->31:15 22:OP:and
31:21->31:21 23:OP:pushr 12
31:26->31:26 24:OP:pushr 13
31:25->31:26 25:OP:not
31:21->31:26 26:OP:and
31:9->31:27 27:OP:or
31:9->31:27 28:OP:list 1
31:2->31:2 29:OP:pushr 2
31:4->31:4 30:OP:pushr 11
31:2->31:5 31:OP:list 2
31:2->31:5 32:OP:list 1
31:2->31:27 33:OP:assign
29:20->32:1 34:OP:end-scope }
29:1->32:1 35:OP:exit-for-range -> 6
29:1->32:1 36:OP:pop
29:1->32:1 37:OP:end-scope
28:15->33:0 38:OP:end-scope
28:9->33:0 39:OP:return
//func2 end
//func3 start 判断函数
anonymous
38:17->48:0 0:OP:new-scope 17
39:21->41:1 1:OP:new-scope 18
39:4->39:6 2:OP:pushid len
39:8->39:8 3:OP:pushr 2
39:7->39:9 4:OP:call vlen:1
39:14->39:16 5:OP:pushid len
39:18->39:18 6:OP:pushr 1
39:17->39:19 7:OP:call vlen:1
39:4->39:19 8:OP:neq
39:21->41:1 9:OP:jmpf -> 16
39:21->41:1 10:OP:new-scope 19
40:9->40:13 11:OP:push false
40:9->40:13 12:OP:list 1
40:2->40:13 13:OP:return
39:21->41:1 14:OP:end-scope
39:21->41:1 15:OP:jmp -> 16
39:21->41:1 16:OP:end-scope
42:1->46:1 17:OP:new-scope 20
42:1->46:1 18:OP:pushleftr 16
42:18->42:18 19:OP:pushr 2
42:1->46:1 20:OP:fast-assign
42:1->46:1 21:OP:enter-for-range -> 45
42:1->46:1 22:OP:range-next
42:5->42:5 23:OP:pushleftr 17
42:8->42:8 24:OP:pushleftr 18
42:5->42:8 25:OP:list 2
42:1->46:1 26:OP:assign
42:20->46:1 27:OP:new-scope 21
43:14->45:2 28:OP:new-scope 22
43:5->43:5 29:OP:pushr 18
43:10->43:10 30:OP:pushr 1
43:12->43:12 31:OP:pushr 17
43:11->43:13 32:OP:push false
43:11->43:13 33:OP:iterablecall off:1 op1: - op2: -
43:5->43:13 34:OP:neq
43:14->45:2 35:OP:jmpf -> 42
43:14->45:2 36:OP:new-scope 23
44:10->44:14 37:OP:push false
44:10->44:14 38:OP:list 1
44:3->44:14 39:OP:return
43:14->45:2 40:OP:end-scope
43:14->45:2 41:OP:jmp -> 42
43:14->45:2 42:OP:end-scope
42:20->46:1 43:OP:end-scope
42:1->46:1 44:OP:exit-for-range -> 22
42:1->46:1 45:OP:pop
42:1->46:1 46:OP:end-scope
47:8->47:11 47:OP:push true
47:8->47:11 48:OP:list 1
47:1->47:11 49:OP:return
38:17->48:0 50:OP:end-scope
38:11->48:0 51:OP:return
//func3 end
据此写出解密脚本
key = [137, 108, 159, 114, 185, 90, 174, 68, 160, 81, 179, 41, 186, 89, 168, 78, 229, 121, 149, 106, 147, 103, 156, 114, 133, 98, 146, 116, 181]
for i in range(29):
if i % 2 == 0:
key[i] ^= 2 * i
key[i] ^= 240
else:
key[i] ^= 2 * i
key[i] ^= 15
for each in key:
print(chr(each), end='')
# yak{A_RE@LW0RLD_5TACKB@SE_VM}
最后 不论是CTF还是写文章本人都处于新手阶段 如有不足之处请见谅

667

被折叠的 条评论
为什么被折叠?



