很有趣的一道题,因素好多
运行文件弹出hook successful,说明用到hook注入,查壳发现文件为32位exe文件,中间说是缺少一个dll文件,直接百度下载过来就可以运行了
定位到main主函数发现原先输出的窗口和代码内的数据不匹配,动态调试发现调用MessageBoxW api时并没有直接调用而是进入了下面这个函数,这是因为win32 api在调用时会触发消息机制,会形成回调函数 ,搞错了,hook和回调函数是两个东西,一个是在消息产生传输时,一个是在api函数被执行完毕,即消息完成了传输。他们都可以用来同时执行另一个可以由用户自定义函数
在这里可以发现将
- Str表中大小写发生了转化
- AddVectoredExceptionHandler函数用于添加一个新的VEH全局异常处理程序。VEH(Vectored Exception Handler)是一种Windows操作系统提供的机制,用于处理来自应用程序的异常。
因为在下面我们可以看到对内存为0的位置发生写入触发了一个异常,即为这里的函数handler开始执行
在这个异常处理函数里面又设置了一个异常处理机制
SetUnhandledExceptionFilter:用于为当前线程设置未处理异常处理程序。当一个未处理的异常导致线程退出时,系统会调用这个处理程序来处理该异常。
可以发现然后将v2当做密钥传入了下一个函数里面,有师傅说可以通过0xA3B1BAC6标识符看出是sm4加密,可恶第一次听说这个加密,标识符Rk[4]={0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC};和md5感觉有点像
接着进入Top函数
先将str2中字符串两两交换位置,看末尾函数发现str2为结尾判断字符串,a1赋值半天好像并没起什么作用,只剩下最后一个加密函数了98126c
为一个base64加密的变式,前面我们知道Str大小写被改变了,而且通过sub_9810ff函数间接赋值,对原结果进行了偏移,偏移了24
所以可以直接看做对base64进行了一个换表 - 更换原表大小写
- 偏移24
综上所述:
- str1为输入flag经过sm4加密然后base64换表加密
- str2原字符串两两字符位置发生交换
wp
#include"stdio.h"
#include"string.h"
int A_a(char *Str);
int encode(char *flag,char *table,int a[]);
int main(){
char key[]="1UTAOIkpyOSWGv/mOYFY4R!!";
char flag[sizeof(key)] ={0};
int num[50]={0};
//int num2[50]={0};
char table[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for(int i=0;i<strlen(key);i+=2){
flag[i] =key[i+1];
flag[i+1] =key[i];
}
puts(flag);
A_a(table);
putchar('\n');
puts(table);
encode(flag,table,num);
putchar('\n');
for(int q=0;q<strlen(flag);q++)
printf("%#x ",num[q]);
//getchar();
return 0;
}
int A_a(char *Str){
char table[65];
for (int i = 0; i < strlen(Str); ++i )
{
if ( Str[i] <= 122 && Str[i] >= 97 )
{
Str[i] -= 32;
}
else if ( Str[i] <= 90 && Str[i] >= 65 )
{
Str[i] += 32;
}
}
for(int j=0;j<64;j++){
table[j] =Str[(24 +j)%64];
}
table[64] =0;
for(int k=0;k<=64;k++){
Str[k] =table[k];
}
return 0;
}
int encode(char *flag,char *table,int a[]){
int temp[60]={0};
int *end=a;
for(int i=0;i<strlen(flag);i++){
for(int j=0;j<64;j++){
if(flag[i] ==table[j]){
temp[i]=j;
break;
}
}
}
for(int k=0,p=0;k<strlen(flag);k+=4,p+=3){
end[p] =(temp[k]<<2) +(temp[k+1]>>4);
end[p+1] =((temp[k+1]&0xf)<<4) +((temp[k+2]&0x3c)>>2);
end[p+2] =((temp[k+2]&0x3)<<6) +temp[k+3];
}
return 0;
}
没找到可以用的sm4解密代码只能用python了
from pysm4 import encrypt, decrypt
num = 0x59d095290df2400614f48d276906874e #密文
key = 0x77686572655f6172655f755f6e6f773f #密钥
num = decrypt(num, key)
print('flag{'+bytes.fromhex(hex(num)[2:]).decode()+'}')
[2:0]从字符串第三个字符到结束
bytes.fromhex() 专门用于从十六进制字符串创建字节串。十六进制字符串中的每两个字符代表一个字节,
所以十六进制字符串的长度必须是偶数。
有点好奇的一点为什么不是小端序输入密文呢
还有直接调试的话似乎不会触发异常,程序会卡死在写入内存为0的时候,看见有debug_hook函数还有Isdebug判断的反调试机制所以这道题里还有些反调试的内容,但没具体发现是在哪里被调用的