reversing.kr(下)

AutoHotkey1

运行文件很常规的对话框,貌似用了某种脚本语言

文件加了upx壳,脱之。脱壳后运行失败

不太清除为啥,在IDA中找到"EXE corrupted"字符串,可以看到一个判断

当然上图是我已经标注后的,很明显,sub_4508c7函数里进行了某种检测,进入该函数,反编译结果如下

int __thiscall sub_4508C7(FILE **this, int a2, char *a3)
{
  FILE **pfp; // esi
  FILE *fp; // eax
  signed int k; // eax
  signed int v7; // eax
  signed int i; // edx
  int offset; // eax
  FILE *fp_; // ST18_4
  int v11; // eax
  signed int v12; // eax
  signed int v13; // edi
  int v14; // edi
  int v15; // ecx
  signed int v16; // [esp-4h] [ebp-550h]
  char v17; // [esp+Ch] [ebp-540h]
  CHAR Filename; // [esp+410h] [ebp-13Ch]
  char v19[16]; // [esp+518h] [ebp-34h]
  char buf1[16]; // [esp+528h] [ebp-24h]
  int v21; // [esp+538h] [ebp-14h]
  int final4Bytes; // [esp+53Ch] [ebp-10h]
  int v23; // [esp+540h] [ebp-Ch]
  int offset_; // [esp+544h] [ebp-8h]
  char v25; // [esp+54Bh] [ebp-1h]
  char *m; // [esp+558h] [ebp+Ch]

  pfp = this;
  sub_450F56(&v17);
  GetModuleFileNameA(0, &Filename, 0x104u);
  fp = fopen(&Filename, unk_46651C);
  *pfp = fp;
  if ( !fp )
    return 1;
  k = 0;
  do
  {
    buf1[k] = byte_466514[k];
    buf1[k + 8] = byte_46650C[k];
    ++k;
  }
  while ( k < 8 );
  v7 = strlen(a3);
  pfp[68] = 0;
  for ( i = 0; i < v7; ++i )
    pfp[68] = (FILE *)((char *)pfp[68] + a3[i]);
  fseek(*pfp, -8, 2);
  fread(pfp + 1, 4u, 1u, *pfp);
  offset = ftell(*pfp);
  fp_ = *pfp;
  offset_ = offset;
  fread(&final4Bytes, 4u, 1u, fp_);
  fseek(*pfp, 0, 0);
  m = 0;
  v11 = 0;
  if ( offset_ > 0 )
  {
    do
    {
      if ( (*pfp)->_flag & 0x10 )
        break;
      fread(&v21, 1u, 1u, *pfp);
      v11 = sub_450F95(&v17, v21);
      ++m;
    }
    while ( (signed int)m < offset_ );
  }
  if ( final4Bytes != (v11 ^ 0xAAAAAAAA) )
    goto LABEL_25;
  fseek(*pfp, (int)pfp[1], 0);
  if ( !fread(v19, 0x10u, 1u, *pfp) )
    goto LABEL_25;
  v12 = 0;
  do
  {
    if ( v19[v12] != buf1[v12] )
      break;
    ++v12;
  }
  while ( v12 < 16 );
  if ( v12 != 16 )
  {
LABEL_25:
    v16 = 3;
LABEL_19:
    v13 = v16;
    fclose(*pfp);
    return v13;
  }
  fread(&v25, 1u, 1u, *pfp);
  if ( v25 != 3 )
  {
    v16 = 4;
    goto LABEL_19;
  }
  fread(&v23, 4u, 1u, *pfp);
  v14 = v23 ^ 0xFAC1;
  fread(pfp + 3, 1u, v23 ^ 0xFAC1, *pfp);       // 取32字节
  sub_450ABA((int)(pfp + 3), v14, v14 + 0xC3D2);
  *((_BYTE *)pfp + v14 + 12) = 0;
  v15 = 0;
  for ( pfp[68] = 0; v15 < v14; ++v15 )
    pfp[68] = (FILE *)((char *)pfp[68] + *((char *)pfp + v15 + 12));
  pfp[2] = (FILE *)ftell(*pfp);
  return 0;
}

具体细节得慢慢进行分析,要对C语言的文件操作函数比较了解,这里大概说下功能

1.取自身文件最后4字节为final4bytes

2.对文件的一块数据部分进行某种运算,获得一个值v11

3.检测final4bytes == v11 ^ 0xaaaaaaaa

4.再向上取文件4字节为offset

5.以offset作为文件偏移位置开始取值,与一些硬编码进行比较

 

分析花了一阵时间,还顺便了解了下FILE结构体,最后4字节可以先不管,可以先把其余地方安排好后动态得到v11并替换文件最后4字节。一开始我去将硬编码替换到了+offset的内存之中,结果后面嵌入的脚本又运行不了,我才发现硬编码本就存在文件之中,只是offset变了,因为upx作为一种压缩壳,很大程度上改变了文件的大小,于是搜索硬编码并将偏移位置替换到offset的位置就行了,由于这种自检测的机制,所以到此为止才算是真正脱了壳吧。

本题的提示如下

 

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

AuthKey = un_md5(DecryptKey) + " " + un_md5(EXE's Key)

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Ex:)

DecryptKey = 1dfb6b98aef3416e03d50fd2fb525600

EXE's Key = c944634550c698febdd9c868db908d9d

=> AuthKey = visual studio

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

By Pyutic 

 

只要分析了程序就会知道,有个md5值会在上面那个函数结尾处全部得到,内存如下

交叉引用到DialogFunc的GetWindowTextA处,下断点开始调试,执行完GetWindowTextA后,对我们的输入下内存断点,运行后会在strcmp函数中断下,栈回溯可以找到两个参数的值,其中一个为

chamd5网站找到两个md5对应字符串,拼接即可  

AutoHotkey2

脱壳和过自检测与AutoHotkey1相同,运行后

根据意思搜索Eddard Stark的私生子就是答案了。

PEPassword

给了两个文件,字面意思是原文件和加了某种保护,确实Packed.exe被查出有壳,但不知道是啥。依次运行,效果如下:

packed.exe

original.exe

这貌似完全不是一个东西。。,不管了,先用IDA打开Packed.exe,啥都看不出来,还是动态调试吧,随便跟一下就能看到一些关键的地方

这里就是消息循环了,直接让程序完全跑起来,当我们输入的时候就会触发键盘消息了。很容易找到消息处理函数,分析后代码如下

可以看到,当edit发生改变时,这里将GetText消息发送出去并将输入存入一个缓冲区中,然后调用一次sub_4091D8函数来进行验证,这个函数目测了一会儿是个复杂哈希函数,但该壳的解密还没看到,于是直接爆破继续往下跟踪,程序会在以下地方动态加载API,然后跳转到代码段执行

那想必在0x4090E0处调用的函数就是解密函数了,进入该函数中。

解密过程:

1.将input经过两次hash生成两个初始密钥eax,ebx

2.使用这两个密钥来对代码段解密

仅根据hash值想找到长度未知的input是很难的,但这里若并非想找input,而是仅仅为了解密成功,是可以找出两个密钥的。首先eax可以直接xor orignal_ep, packed_ep来找到,所以问题就是ebx密钥了。在解密过程中,由于下一轮解密的eax是通过这一轮的ebx得到的,而下一轮的eax我们也是已知的,所以从理论上是可以求出ebx的,但这里在过程上不可逆,所以可以考虑蛮力攻击。

枚举空间为2的32次方,貌似有点大,但这里只有几条汇编指令,要跑起来所需要的时间应该不会太久。结果1分钟都没要到就跑完了。。。暴破代码:

#include <cstdlib>
#include <cstdio>

unsigned GetNextEax(unsigned _eax, unsigned _ebx)
{
	unsigned ret = 0;
	_asm {
		mov eax, _eax
		mov ebx, _ebx
		mov cl, al
		rol ebx, cl
		xor eax, ebx
		mov cl, bh
		ror eax, cl
		mov ret, eax
	}
	return ret;
}

int main()
{
	unsigned packed_ep = 0xb6e62e17;
	unsigned orignal_ep = 0x014cec81;
	unsigned packed_next = 0x0d0c7e05;
	unsigned orignal_next = 0x57560000;
	unsigned _eax = packed_ep ^ orignal_ep;
	unsigned eax_next = packed_next ^ orignal_next;
	for (unsigned _ebx = 0; _ebx < 0xfffffffff; _ebx++)
	{
		if (eax_next == GetNextEax(_eax, _ebx))
			printf("ebx:0x%x\n", _ebx);
		if (_ebx == 0xffffffff)
			break;
	}
	system("pause");
}

待续未完。。。 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值