KoOh

这道题如果先去找主函数的方法,来到了这里,是一个base64加密,点开那个参数

应该是base64加密变表

import base64
import string

str1 = "zMXHz3TMywTLx2zSywCHzMfRzv9MBgfNiwzHA2vFzMXHzYeHiseHisf9"

string1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

print (base64.b64decode(str1.translate(str.maketrans(string1,string2))))
#flag{fake_flag!fake_flag!fake_flag!!!!!!!}

错误的flag,此时我们观察上图发现下面有一些字符串,看看交叉引用

发现有一大串代码是处于爆红状态,发现有花指令,这个时候反编译

此时看到这个hook,很明显是先解密那串很奇怪的字符串,解密之后是ida.exe,ollydbg等等,拍进程快照然后判断是不是在运行这些进程来反调试

这个时候如果发现在调试的化,就会退出,这里的方法就是将eax的值设置为0,其实我是静态看的。

之后发现了rc4的变种

这里其实很明显的rc4,交exp

注意两个点:
1.这里的rc4加密魔改点是最后的异或变成了-

2.密钥被替代了

当我去跟踪这些散落的代码的时候,发现他们的最开始引用都是在Tlscallback函数里面,也就是说都先于主函数进行

#include<stdio.h>

/*
RC4初始化函数
*/
void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len_k)
{
int i = 0, j = 0;
char k[256] = { 0 };
unsigned char tmp = 0;
for (i = 0; i < 256; i++) {
s[i] = i;
k[i] = key[i % Len_k];
}
for (i = 0; i < 256; i++) {
j = (j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}

/*
RC4加解密函数
unsigned char* Data 加解密的数据
unsigned long Len_D 加解密数据的长度
unsigned char* key 密钥
unsigned long Len_k 密钥长度
*/
void rc4_crypt(unsigned char* Data, unsigned long Len_D, unsigned char* key, unsigned long Len_k) //加解密
{
unsigned char s[256];
rc4_init(s, key, Len_k);
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for (k = 0; k < Len_D; k++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
t = (s[i] + s[j])%256 ;
Data[k] = (unsigned char)((int)Data[k] +(int)s[t]);

}
}
void main()
{
//字符串密钥
unsigned char key[] = "DDDDAAAASSSS";
unsigned long key_len = sizeof(key)-1 ;
//数组密钥
//unsigned char key[] = {};
//unsigned long key_len = sizeof(key);

//加解密数据
unsigned char data[] = { 0x18, 0x9C, 0x47, 0x3D, 0x3B, 0xE1, 0x29, 0x27, 0x9F, 0x34,
0x83, 0xD5, 0xED, 0xB5, 0x6E, 0x59, 0x7F, 0xDE, 0x47, 0xD7,
0x65, 0x3F, 0x7A, 0x33, 0x5B, 0x64, 0xB6, 0xFA, 0x94, 0x55,
0x87, 0x42, 0x20, 0x06, 0x0C, 0x69, 0xFE, 0x72, 0xA9, 0xE4,
0xD1, 0x7C
};


//加解密
rc4_crypt(data, sizeof(data), key, key_len);

for (int i = 0; i < sizeof(data); i++)
{
printf("%c", data[i]);
}
printf("\n");
return;
}
//zstuctf{xXx_team_Is_GooD

ez_RE

进来发现了一个随机数种子,跟md5有关,接着是一个异或随机数,这里点开生成种子看看

这段代码的具体意思是将函数的前1024个字节当种子,这里可能操作系统不同的化,编译器不同,电脑不同

代码中利用了 custom_md5_init 函数的内存布局作为加密输入的一部分。所谓“内存布局”,是指函数在运行时被加载到内存后,具体的机器指令、数据和偏移地址的排列形式。由于内存布局会受到编译器、操作系统、以及某些安全机制(例如地址空间随机化 ASLR)的影响,可能在不同运行环境下表现出不同的动态特性。

那怎么办,可以试试爆破种子。但是必须在Linux环境去爆破,

具体Linux命令是

vim ac.cpp
gcc ac.cpp -o ae
如果是c++
g++ ac.cpp -o ae
./ae
#include <iostream>
#include <string>
#include <vector>
int main()
{
unsigned char Enc[] =
{
0x5C, 0x76, 0x4A, 0x78, 0x15, 0x62, 0x05, 0x7C, 0x6B, 0x21,
0x40, 0x66, 0x5B, 0x1A, 0x48, 0x7A, 0x1E, 0x46, 0x7F, 0x28,
0x02, 0x75, 0x68, 0x2A, 0x34, 0x0C, 0x4B, 0x1D, 0x3D, 0x2E,
0x6B, 0x7A, 0x17, 0x45, 0x07, 0x75, 0x47, 0x27, 0x39, 0x78,
0x61, 0x0B
};
// Crack!!!
for(long long i=0xB0000000;i<0xC0000000;i++)
{
srand(i);
int randlist[42]{};
for(int j=0;j<42;j++)
randlist[j]=rand()%127;
if(randlist[0] == (0x5C^'f')
&& randlist[1] == (0x76^'l')
&& randlist[2] == (0x4A^'a')
&& randlist[3] == (0x78^'g')
&& randlist[4] == (0x15^'{')
)
{
std::cout<<i<<std::endl;
}
}
std::cin.get();
//output: 3021285795
return 0;
}

这个爆破范围不是很确定,应该可以慢慢试,就小32位,不是很大,

这里注意,因为这是linux文件,他们的c库不同,环境不同,所以exp必须在linux环境中跑

flag{b799eb3a-59ee-4b3b-b49d-39080fc23e99}