[安洵杯 2019]crackMe 1

很有趣的一道题,因素好多
运行文件弹出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判断的反调试机制所以这道题里还有些反调试的内容,但没具体发现是在哪里被调用的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值