首先先用exeinfope查一下壳
没有加壳,64位的程序 ,拉入ida64进行分析
这两个肯定有一个里面有主函数,我们都点进去看看
sub_402E50()
确实看不出什么东西
sub_401180()
往下翻翻,看到initenv 初始环境的意思,所有main函数很可能在下面
继续跟sub_4015F0()
这题其实是个双线程问题,就是父进程(else后的内容)执行后,担任调试器的角色,去调用if中的 sub_4026EA()函数
注意一点:
当我们在调试这个程序的时候,会有报错
这里报错的原因应该是分母为0导致的
在子进程中V19=1,打印出flag
所以关键是看DebugEvent.dwDebugEventCode == 1的活动:接受处理来自子进程的异常,进而修改子进程代码
SMC的题目,我们就让它自己跑起来解密就行了
关键代码还是在调试的子线程中,我们分析一下
为什么会程序自报错?
原本两个进程是互不相关的,当子进程产生错误后,返回给父进程,父进程才知道要进行处理了,但是也不是一直处理,所以就会出现另外一个错误,告诉父进程处理完了,可以停止了。
所以现在关键就是要去寻找子进程要执行函数中出现触发异常地方
继续分析子进程
加密逻辑主要就关注到sub_401CA7
点进去是这样的,我们发现很多代码被混淆了
这里前面会有int 3触发断点,后面还有很多错误指令,实际是一个smc,那可以猜到就是先触发断点后被主进程调试器所捕获,然后进行解密,之后被调试进程继续运行
我们写脚本跑一下SMC,这里直接贴上官方WP的脚本
下面展示一下
#include <idc.idc>
static main(){
auto addr = 0x401E1F;
auto i = 0;
for(i=0;i<0x57E;i++){
PatchByte(addr + i,Byte(addr + i) ^i);
}
}
在函数开头按d 解析成数据
将黄色部分全部选中 按c 解析成代码
将int 3 nop掉
我们发现rip+2
直接跳到两个字节之后,patch混淆的三个字节
现在所有代码都红了,直接全选,按p创建函数,f5反编译
加密代码就出来了
返回之前的子进程中看了下传参,第一次参数密钥credentials,第二个是email
这是加密流程
加密操作不复杂,查看验证函数
就是把邮箱密文和密钥密文按照-的分割来分别读取出来,最后把密钥最后一次与邮箱密文的异或加密给异或回去,经过这个解密操作后进行比较
但是这还没完,因为这个验证数组是被修过的,在主进程进行调试的某一时刻会重新修改此处内存,这一部分的实现主要是通过管道通信和环境变量的设置来完成的
子进程在这里活得自己进程check数组的储存位置后利用v24/=Buffer[19]触发除零异常,在这之前讲内存地址用writefile写到管道中,子进程捕获异常后获取地址,修改内存位置的值,处理异常,子程序继续执行,但是check数组已被改变。
处理除零异常,此处sub_402545进行修改内存,进行了加花,patch即可,改call+ret+pop为jmp即可
大概就分析完了,其实还是挺有难度的,我的思路也比较乱,把网上各位师傅的WP都翻看了下,进行了总结
最后贴上大师傅的脚本
#include
#include
#include
void map(char key,int *x,int *y){
int i = 0,j = 0;
char table[9][9]={'\0'};
strcpy(table[0],"ABCDEFGH");
strcpy(table[1],"12345678");
strcpy(table[2],"0IJKLMNO");
strcpy(table[3],"+OPQRStu");
strcpy(table[4],"\\vwxyzTU");
strcpy(table[5],"abcdefgh");
strcpy(table[6],"VWXYZijk");
strcpy(table[7],"lmnopqrs");
for(i=0;i<8;i++){
for(j=0;j<8;j++){
if(table[i][j]==key){
*x = i;
*y = j;
return ;
}
}
}
}
int main()
{
int x,y,z;
int count = 0;
int i = 0,j = 0,k = 0;
char tmp[10]={'\0'};
int result[100]={0};
char plain[376]={'\0'};
int flag[376]={29,110,78,63,57,58,40,41,23,20,55,70,67,48,17,18,45,46,2,12,48,49,50,62,37,38,5,118,94,45,15,12,29,30,63,76,102,
21,56,59,21,22,6,117,111,28,3,0,13,124,127,3,16,108,122,11,5,6,42,43,33,82,125,14,80,83,127,124,91,90,86,88,108,16,6,119,113,114,
80,81,125,14,17,98,120,123,107,104,118,120,126,112,113,112,67,64,93,81,70,58,5,121,66,76,121,122,87,38,35,95,74,68,109,108,108,111,
73,74,102,103,84,90,94,80,99,98,82,81,189,190,157,156,169,168,151,153,173,209,198,183,177,178,144,227,220,160,183,185,139,138,187,184,
165,166,183,182,130,241,221,174,190,176,134,138,153,232,229,150,184,185,180,199,225,146,128,131,141,142,162,163,165,164,171,216,247,132,
148,231,241,128,131,128,208,163,129,242,233,232,217,216,230,231,213,214,241,242,209,162,147,146,144,227,196,197,201,200,199,196,231,228,
193,192,240,241,240,241,252,143,166,213,248,251,213,214,199,180,141,140,163,208,222,223,236,237,233,234,203,186,186,201,231,148,176,204,
219,213,46,47,44,47,57,58,22,23,23,22,23,25,41,85,65,64,82,46,55,59,41,42,6,117,84,40,63,49,48,62,58,52,13,126,110,31,25,26,57,74,73,72,
101,22,60,61,2,12,21,105,126,15,9,10,43,88,116,7,22,24,25,23,47,46,109,30,0,113,121,122,106,25,4,119,100,23,15,115,106,100,77,76,66,65,105,
24,27,26,27,26,22,101,66,76,122,6,45,44,46,95,89,90,118,119,117,123,78,64,115,0,33,82,96,110,86,42,54,71,75,120};
for(i=374;i>=0;i--){
flag[i] = flag[i] ^ i ^ flag[i+1];
}
for(i=0;i<376;i+=2){
map(flag[i],&x,&y);
map(flag[i+1],&y,&z);
plain[j++] = ((x << 6)|(y << 3)|(z));
}
j = 0;
for(i=0;i=2;i--){
result[i] = result[i] - result[i-1] - result[i-2];
}
for(i=0;i