侧边栏壁纸
博主头像
Fup1p1 's Blog 博主等级

梦想是财富自由~

  • 累计撰写 38 篇文章
  • 累计创建 24 个标签
  • 累计收到 9 条评论

目 录CONTENT

文章目录

【Reverse】【虎符CTF 2022】 the_shellcode 复现

Fup1p1
2022-11-11 / 0 评论 / 0 点赞 / 1152 阅读 / 0 字 / 正在检测是否收录...

脱壳

查壳

DIE是查不出来滴,使用Exeinfope查壳。
QQ截图20221111221333
是个强壳,有点难搞。但是我们还是一个目标:找到OEP,给他dump下来。

只修改标志符是骗不了Themida的,在PEB中的BeingDebugged被设为True后,还会有一些其他的变化产生。
加载时会将PEB中的NtGlobalFlag中的一个位改变,使其值为0x70,而正常状态下不是
在WRK中有一个宏也会随着NtGlobalFlag的改变而在RtlCreateHeap中用RtlDebugCreateHeap创建调试堆。这个调试堆中含有大量的标志(例如0xBAAD0F0D和0xFEEEFEEE等),而正常情况下这个地址中却没有有意义的数据。
单纯的修改BeingDebugged标志位而忘记清除其他痕迹时,经常会被有所防备的壳、反调等程序捕捉到,例如Themida

脱壳

0x01 使用scyllahide(x32dbg)

选择Themida,插件能直接过掉反调试。
找到OEP,用Scylla直接dump下来,Fix Dump。
但是有部分IAT表未修复。
IDA解析后会出现__24等怪异的函数

0x02 使用SharpOD(Ollydbg/x32dbg)

记得勾上Protect Drx

其他步骤同上。

若如果想彻底恢复IAT表,可以看P.Z的Blog

开始逆向分析

第一段输入

QQ截图20221121200709
一开始输入长度为352位的shellcode
后面的函数进入查看,发现是base64的解码函数(8位变6位)
base64de

左移3位,后面右移三位还原即可
rol3

XXTEA小魔改(z>>6),key值已知,熟悉XXTEA的都知道,0x61C88647值是特征值(0x9e3779b)的取反值,所以此处是-delta。
xxtea

密文也已知
XXTEADATA
直接提取66个Dw(352/4*3/4)
tiqu

第二段输入

现在明白为什么题目叫shellcode了。
QQ截图20221121202700
我们先写脚本,得到shellcode Base64解密后的值。

#include <stdio.h>
#include <stdlib.h>
#define delta 0x9e3779b9
char basetable[]={
    0x42,0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x40, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x3E, 0x42, 0x42, 0x42, 0x3F, 0x34, 0x35, 0x36, 
  0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x42, 0x42, 0x42, 
  0x41, 0x42, 0x42, 0x42, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 
  0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x1A, 0x1B, 0x1C, 0x1D, 
  0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 
  0x32, 0x33, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 
  0x42, 0x42, 0x42, 0x42, 0x42
};
int FindIndex(int x)
{
	int i;
	
	for ( i = 0; i < 256; i++ )
		if ( basetable[i] == x )
			return i;
}

void BaseDecode(unsigned char * flag, int len, unsigned char * input)
{
	int i, j;
	
	for ( i = 0, j = 0; i < len; i += 3, j += 4 )
	{
	 	input[j] = (flag[i] >> 2) & 0x3F;
	 	input[j + 1] = ((flag[i] & 0x3) << 4) | (flag[i + 1] & 0xF0 ) >> 4;
	 	input[j + 2] = ((flag[i + 1] & 0xF ) << 2) | (flag[i + 2] & 0xC0) >> 6;
	 	input[j + 3] = flag[i + 2] & 0x3F;
	}
	for ( i = 0; i < len / 3 * 4; i++ )
		input[i] = FindIndex(input[i]);
}
 template<class T> T ROL(T value, int count)

{

  const unsigned int nbits = sizeof(T) * 8;

 

  if ( count > 0 )

  {

    count %= nbits;

    T high = value >> (nbits - count);

    if ( T(-1) < 0 ) // signed value

      high &= ~((T(-1) << count));

    value <<= count;

    value |= high;

  }

  else

  {

    count = -count % nbits;

    T low = value << (nbits - count);

    value >>= count;

    value |= low;

  }

  return value;

}
int main()
{
    unsigned int v[66] = { 0x4B6B89A1, 0x74C15453, 0x4092A06E, 0x429B0C07, 0x40281E84, 0x8B5B44C9, 0x66FEB37B, 0x3C77A603, 
    0x79C5892D, 0x0D7ADA97, 0x1D51AA56, 0x02D4D703, 0x4FA526BA, 0x32FAD64A, 0x0C0F6091, 0x562B7593, 
    0xDB9ADD67, 0x76165563, 0xA5F79315, 0x3AEB991D, 0x1AB721D4, 0xAACD9D2C, 0x825C2B27, 0x76A7761A, 
    0xB4005F18, 0x117F3763, 0x512CC540, 0xC594A16F, 0xD0E24F8C, 0x9CA3E2E9, 0x0A9CC2D5, 0x4629E61D, 
    0x637129E3, 0xCA4E8AD7, 0xF5DFAF71, 0x474E68AB, 0x542FBC3A, 0xD6741617, 0xAD0DBBE5, 0x62F7BBE3, 
    0xC8D68C07, 0x880E950E, 0xF80F25BA, 0x767A264C, 0x9A7CE014, 0x5C8BC9EE, 0x5D9EF7D4, 0xB999ACDE, 
    0xB2EC8E13, 0xEE68232D, 0x927C5FCE, 0xC9E3A85D, 0xAC74B56B, 0x42B6E712, 0xCD2898DA, 0xFCF11C58, 
    0xF57075EE, 0x5076E678, 0xD4D66A35, 0x95105AB9, 0x1BB04403, 0xB240B959, 0x7B4E261A, 0x23D129D8, 
    0xF5E752CD, 0x4EA78F70};
    unsigned int key[4] = {116,111,114,97};
    unsigned int sum = 0;
    unsigned int y,z,p,rounds,e;
    int n = 66;
    int i = 0;
    rounds = 6 + 52/n;
    y = v[0];
    sum = rounds*delta;
     do
     {
        e = sum >> 2 & 3;
        for(p=n-1;p>0;p--)
        {
            z = v[p-1];
            v[p] -= ((((z>>6)^(y<<2))+((y>>3)^(z<<4))) ^ ((key[(p&3)^e]^z)+(y ^ sum)));
            y = v[p];
        }
        z = v[n-1];
        v[0] -= (((key[(p^e)&3]^z)+(y ^ sum)) ^ (((y<<2)^(z>>6))+((z<<4)^(y>>3))));
        y = v[0];
        sum = sum-delta;
     }while(--rounds);
    unsigned char *t=(unsigned char*)v;
    unsigned char basecode[66*4];
    for (int i = 0; i < n*4; i++)
    {
        basecode[i]=ROL(t[i],-3);
        printf("%x ",basecode[i]);
    }
     unsigned char input[352];
    BaseDecode(basecode, 66 * 4, input);
    for ( i = 0; i < 352; i++ )
    	printf("%c", input[i]);
    return 0;
}

得到的数据,使用16进制编辑工具写入,再用IDA打开,最后解析。
QQ截图20221121204722
QQ截图20221121205121
加密函数的第二个参数是flag,加密过程过于冗余,直接看含flag的代码段。
QQ截图20221121205659
逻辑并不复杂,n1,n2分别运算后,最后进行比较.
因为n1,n2相等,我们可以化简这两个等式(设v19为data1,v14为data2)

n2=data1[i]
n1=flag[i]-data2][i]%5

即flag[i]=data1[i]+data2[i]%5
我们可以通过动态调试来拿到data1和data2的数据。
QQ截图20221121211422
QQ截图20221121211406
找到加密函数的call指令对应的偏移,加上OD中的基址
QQ截图20221121212104
F7步入,IDA中查看data1,data2的偏移(0X7A,0x96),在OD找到对应地址,观察寄存器的值
QQ截图20221121212219
QQ截图20221121212535

编写脚本

char data2[]="LoadLibraryExA";
char data1[]="is program can";
char flag[]={};
puts("\n");
for (int i = 0; i < sizeof(data1); i++)
{
	printf("%c",data1[i]+data2[i]%5);
}
//jt"psojvcq!gan

jt"psojvcq!gan加上shellcode的值,最后MD5,就是flag了。

0

评论区