the_shellcode

用ida载入之后,显然这个地方被加壳了,这里是Themida壳

image-20220322202138711

定位到OPE

这是是使用插件直接反反调试

sharpOD

安装sharpOD,设置其中的配置:主要时要勾上图中标注的那个选项(这个可以去程序中的反调试)

image-20220415130826836

按f9就能够运行起程序,就能够运行起程序了

image-20220415131021698

OPE定位并且下硬件断点

按E打开可执行模块窗口

可执行模块窗口:(快捷键:Alt+E)列出了当前被调试进程加载的所有可执行模块。它也显示了很多有用的信息,比如模块大小、入口地址、模块版本、以及可执行文件路径等。

image-20220415131149355

打开该模块我们看到时一堆乱码,在这里我们需要去掉模块分析(汇编窗口,右键 -> 分析 -> 从模块中删除分析)

image-20220415132210877

通过查找程序执行时输出的字符串 “please input the shellcode:” 定位到程序的正真入口的地方

右键->Search for -> All referenced text strings

image-20220415132424418

image-20220415132625126

通过上面的字符串表我们就到达了程序的入口处了 push ebp的位置,我们就直接在这个地方下断点(方便之后直接定位到程序的入口)

image-20220415132847653

这个地方需要下硬件断点,这样定位到的才是这个代码的位置(因为重调之后这片数据又会成为未解压缩的状态),程序的入口的位置是 0x9111c0

image-20220415133232350

再次运行程序就能够直接到达程序的入口点位置了

dump和修复IAT表

直接dump下来的程序中的函数不能简单明了的知道它的作用,修复之后的代码更易懂

直接dump程序

使用Ollydump就可以将程序dump下来

在内存映射窗口查看起始地址 为910000

image-20220415140509813

设置起始地址和入口点地址,注意入口点位置是偏移地址

image-20220415140738089

因为这个程序里面的输入表有修改,所以这个地方dump出来的程序是不能够运行的

将dump出来的这个程序放入ida之中查看,通过字符串定位到关键代码的位置

这里的符号表没有修复,所以程序里面的函数不知道其含义,作用

image-20220415141612009

未修复的IAT表,已经修复的是能够直接知道函数的作用的,未修复的是直接用地址作为函数名的

image-20220415142913315

image-20220415143302046

可以看到未修复的IAT就是通过不断地跳转到达目标函数地位置,动态调试地方式跟一下看一下函数地执行过程

跟未修复的IAT表的过程

我们要跟地是未修复地,图中地第一个函数,可以知道它是已经修复地,第二个是未修复地,所以我们要跟进地是第二个

image-20220415144031639

F7跟进之后可以看到又是一个跳转,没有到达目标地代码

image-20220415144320314

又跟进入,又是一个跳转

image-20220415144349910

又跟进去,在这个页面之中我们Ctrl+F9,到达ret的地方

image-20220415144516292

查看它的堆栈,就看到它真正调用的函数名称

image-20220415144604045

通过这样的特性,我们编写脚本进行修复

修复IAT表(脚本+Scylla)

去掉不需要修复的IAT:

  • IAT已经到达结束位置
  • IAT大于72C0 0000(说明IAT是正确指向)
  • IAT表的值为0(就不需要修复了)

脚本:(从上面我能知道我的基址是0x910000)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
VAR OEP
MOV OEP, 009111C0

VAR IATAddr
VAR tmpAddr
MOV IATAddr, 00912FFC

RepairIATTable:
ADD IATAddr, 4
MOV tmpAddr, [IATAddr]
CMP tmpAddr, 72C00000 // IAT的正确指向
JA RepairIATTable // 无符号大于则跳转(大于 72C00000 这个地址是正确的IAT)

CMP tmpAddr, 0 // IAT的值是0 这个不需要修复
JE RepairIATTable // 等于则跳转(如果是等于0是没必要修复的)

MOV eip, tmpAddr
RTR
MOV [IATAddr], [esp]
CMP IATAddr, 009130E0 // 已经到达结束位置
JAE Success // 无符号大于等于则跳转(当大于这个结束的位置是错误的需要进行修复)
JMP RepairIATTable // JMP 无条件跳转

Success:
MOV eip, OEP
RET

运行完之后我们就能看到IAT被修复了

image-20220415150518388

现在就需要使用,[Scylla](输入表 (pediy.com))修复一下这个IAT表,再dump出来

用管理员权限打开Scylla x86,设置入口点,获得IAT表

image-20220415154056291

得到输入表,并且删除破坏的表

image-20220415154211083

先将程序 Dump,再对应dump下来的程序 Fix Dump

用ida打开这个修复的文件

image-20220415154525798

再打开程序除去作者编译的时候去掉的符号表,其它的IAT就被修复好了

image-20220415154727563

代码分析1

xxtea解密

xxtea加密,但是注意里面有变形

对比标准的xxtea的MX:MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

这里的变形成:MX (((z>>6^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

image-20220415163307268

key值:116,111,114,97

image-20220415163538840

xxtea对比的数据:

1
2
3
4
5
6
7
8
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

xxtea的key:

1
116,111,114,97

xxtea解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>6^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

void btea(uint32_t *v, int n, uint32_t const key[4])
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) /* Coding Part */
{
rounds = 6 + 52/n;
sum = 0;
z = v[n-1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++)
{
y = v[p+1];
z = v[p] += MX;
}
y = v[0];
z = v[n-1] += MX;
}
while (--rounds);
}
else if (n < -1) /* Decoding Part */
{
n = -n;
rounds = 6 + 52/n;
sum = rounds*DELTA;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--)
{
z = v[p-1];
y = v[p] -= MX;
}
z = v[n-1];
y = v[0] -= MX;
sum -= DELTA;
}
while (--rounds);
}
}

void rolR(uint32_t tem)
{

}
int main()
{
uint32_t v[67]= {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,0x0};
uint32_t const k[4]= {116,111,114,97};
int n= 66; //n的绝对值表示v的长度,取正表示加密,取负表示解密
btea(v, -n, k);
for(int i=0;i<66;i++){
printf("0x%x,",(uint32_t *)v[i]);
}
return 0;
}

xxtea解密之后的数据

1
2
3
4
5
6
7
8
9
10
11
0x6243e703,0x993831bb,0x925c2396,0x60925c81,0x5ca0925c,0xbd784193,
0xff993152,0xe1650699,0x6110e30b,0x687e0e01,0x8717c718,0x925cba92,
0xe1125c80,0x25c1618,0x78062cc3,0xf524,0x82161800,0x5cc0425c,
0xd61801c2,0x7800cf1c,0x4d24,0xa15c4a00,0x9997185c,0x650699ff,
0x18687e0e,0xab26d1c7,0x21e318a7,0x21e3d920,0x99ceab60,0x1c4e99ff,
0xb5788216,0x7e0e5020,0xac71868,0xab70cf1c,0x687e0e8f,0x99ff99ba,
0x21a25c4e,0xb57892e1,0x3bc570e0,0xbf333333,0x5cd78e5f,0xf8470e16,
0x206c1618,0xd2c65904,0x5020b578,0x7e0e1e59,0xac71868,0xab70cf1c,
0x687e0ea6,0xa321e1d9,0x9b2943b0,0x265c0000,0x7b7343,0x5c82a200,
0xff4221e2,0x43a05f9e,0x9b29,0xcb43265c,0xa2009b2b,0x21e25c82,
0xc29eff42,0xc2c2c2c2,0xc2c2c2c2,0xfac21e0b,0x4f905cd2,0xffffff58

循环右移

循环右移3位:(每8位数)

image-20220415203305044

脚本:

1
2
3
4
src = [0x03,0xe7,0x43,0x62,0xbb,0x31,0x38,0x99,0x96,0x23,0x5c,0x92,0x81,0x5c,0x92,0x60,0x5c,0x92,0xa0,0x5c,0x93,0x41,0x78,0xbd,0x52,0x31,0x99,0xff,0x99,0x06,0x65,0xe1,0x0b,0xe3,0x10,0x61,0x01,0x0e,0x7e,0x68,0x18,0xc7,0x17,0x87,0x92,0xba,0x5c,0x92,0x80,0x5c,0x12,0xe1,0x18,0x16,0x5c,0x02,0xc3,0x2c,0x06,0x78,0x24,0xf5,0x00,0x00,0x00,0x18,0x16,0x82,0x5c,0x42,0xc0,0x5c,0xc2,0x01,0x18,0xd6,0x1c,0xcf,0x00,0x78,0x24,0x4d,0x00,0x00,0x00,0x4a,0x5c,0xa1,0x5c,0x18,0x97,0x99,0xff,0x99,0x06,0x65,0x0e,0x7e,0x68,0x18,0xc7,0xd1,0x26,0xab,0xa7,0x18,0xe3,0x21,0x20,0xd9,0xe3,0x21,0x60,0xab,0xce,0x99,0xff,0x99,0x4e,0x1c,0x16,0x82,0x78,0xb5,0x20,0x50,0x0e,0x7e,0x68,0x18,0xc7,0x0a,0x1c,0xcf,0x70,0xab,0x8f,0x0e,0x7e,0x68,0xba,0x99,0xff,0x99,0x4e,0x5c,0xa2,0x21,0xe1,0x92,0x78,0xb5,0xe0,0x70,0xc5,0x3b,0x33,0x33,0x33,0xbf,0x5f,0x8e,0xd7,0x5c,0x16,0x0e,0x47,0xf8,0x18,0x16,0x6c,0x20,0x04,0x59,0xc6,0xd2,0x78,0xb5,0x20,0x50,0x59,0x1e,0x0e,0x7e,0x68,0x18,0xc7,0x0a,0x1c,0xcf,0x70,0xab,0xa6,0x0e,0x7e,0x68,0xd9,0xe1,0x21,0xa3,0xb0,0x43,0x29,0x9b,0x00,0x00,0x5c,0x26,0x43,0x73,0x7b,0x00,0x00,0xa2,0x82,0x5c,0xe2,0x21,0x42,0xff,0x9e,0x5f,0xa0,0x43,0x29,0x9b,0x00,0x00,0x5c,0x26,0x43,0xcb,0x2b,0x9b,0x00,0xa2,0x82,0x5c,0xe2,0x21,0x42,0xff,0x9e,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0x0b,0x1e,0xc2,0xfa,0xd2,0x5c,0x90,0x4f,0x58,0xff,0xff,0xff]
for i in range(len(src)):
src[i] = ((src[i]>>3)&0xff) | ((src[i]<<5)&0xff)
print("0x"+hex(src[i])[2:].zfill(2),end=",")
1
2
3
4
5
6
7
8
9
10
11
12
13
0x60,0xfc,0x68,0x4c,0x77,0x26,0x07,0x33,0xd2,0x64,0x8b,0x52,0x30,0x8b,0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,
0x28,0x0f,0xb7,0x4a,0x26,0x33,0xff,0x33,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x03,0xf8,
0xe2,0xf0,0x52,0x57,0x8b,0x52,0x10,0x8b,0x42,0x3c,0x03,0xc2,0x8b,0x40,0x78,0x85,0xc0,0x0f,0x84,0xbe,0x00,
0x00,0x00,0x03,0xc2,0x50,0x8b,0x48,0x18,0x8b,0x58,0x20,0x03,0xda,0x83,0xf9,0x00,0x0f,0x84,0xa9,0x00,0x00,
0x00,0x49,0x8b,0x34,0x8b,0x03,0xf2,0x33,0xff,0x33,0xc0,0xac,0xc1,0xcf,0x0d,0x03,0xf8,0x3a,0xc4,0x75,0xf4,
0x03,0x7c,0x24,0x04,0x3b,0x7c,0x24,0x0c,0x75,0xd9,0x33,0xff,0x33,0xc9,0x83,0xc2,0x50,0x0f,0xb6,0x04,0x0a,
0xc1,0xcf,0x0d,0x03,0xf8,0x41,0x83,0xf9,0x0e,0x75,0xf1,0xc1,0xcf,0x0d,0x57,0x33,0xff,0x33,0xc9,0x8b,0x54,
0x24,0x3c,0x52,0x0f,0xb6,0x1c,0x0e,0xb8,0x67,0x66,0x66,0x66,0xf7,0xeb,0xd1,0xfa,0x8b,0xc2,0xc1,0xe8,0x1f,
0x03,0xc2,0x8d,0x04,0x80,0x2b,0xd8,0x5a,0x0f,0xb6,0x04,0x0a,0x2b,0xc3,0xc1,0xcf,0x0d,0x03,0xf8,0x41,0x83,
0xf9,0x0e,0x75,0xd4,0xc1,0xcf,0x0d,0x3b,0x3c,0x24,0x74,0x16,0x68,0x25,0x73,0x00,0x00,0x8b,0xc4,0x68,0x6e,
0x6f,0x00,0x00,0x54,0x50,0x8b,0x5c,0x24,0x48,0xff,0xd3,0xeb,0x14,0x68,0x25,0x73,0x00,0x00,0x8b,0xc4,0x68,
0x79,0x65,0x73,0x00,0x54,0x50,0x8b,0x5c,0x24,0x48,0xff,0xd3,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,
0x61,0xc3,0x58,0x5f,0x5a,0x8b,0x12,0xe9,0x0b,0xff,0xff,0xff

base解密

这个地方的逆运算实际上是base系列的加密

每三个元素为一组,然后每次去6位的数,这个六位的数在表中的索引是什么

image-20220415203354030

base的表:(注意数据的顺序)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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

分析代码逆向解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
table = [  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]
src = [0x60,0xfc,0x68,0x4c,0x77,0x26,0x07,0x33,0xd2,0x64,0x8b,0x52,0x30,0x8b,0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x33,0xff,0x33,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x03,0xf8,0xe2,0xf0,0x52,0x57,0x8b,0x52,0x10,0x8b,0x42,0x3c,0x03,0xc2,0x8b,0x40,0x78,0x85,0xc0,0x0f,0x84,0xbe,0x00,0x00,0x00,0x03,0xc2,0x50,0x8b,0x48,0x18,0x8b,0x58,0x20,0x03,0xda,0x83,0xf9,0x00,0x0f,0x84,0xa9,0x00,0x00,0x00,0x49,0x8b,0x34,0x8b,0x03,0xf2,0x33,0xff,0x33,0xc0,0xac,0xc1,0xcf,0x0d,0x03,0xf8,0x3a,0xc4,0x75,0xf4,0x03,0x7c,0x24,0x04,0x3b,0x7c,0x24,0x0c,0x75,0xd9,0x33,0xff,0x33,0xc9,0x83,0xc2,0x50,0x0f,0xb6,0x04,0x0a,0xc1,0xcf,0x0d,0x03,0xf8,0x41,0x83,0xf9,0x0e,0x75,0xf1,0xc1,0xcf,0x0d,0x57,0x33,0xff,0x33,0xc9,0x8b,0x54,0x24,0x3c,0x52,0x0f,0xb6,0x1c,0x0e,0xb8,0x67,0x66,0x66,0x66,0xf7,0xeb,0xd1,0xfa,0x8b,0xc2,0xc1,0xe8,0x1f,0x03,0xc2,0x8d,0x04,0x80,0x2b,0xd8,0x5a,0x0f,0xb6,0x04,0x0a,0x2b,0xc3,0xc1,0xcf,0x0d,0x03,0xf8,0x41,0x83,0xf9,0x0e,0x75,0xd4,0xc1,0xcf,0x0d,0x3b,0x3c,0x24,0x74,0x16,0x68,0x25,0x73,0x00,0x00,0x8b,0xc4,0x68,0x6e,0x6f,0x00,0x00,0x54,0x50,0x8b,0x5c,0x24,0x48,0xff,0xd3,0xeb,0x14,0x68,0x25,0x73,0x00,0x00,0x8b,0xc4,0x68,0x79,0x65,0x73,0x00,0x54,0x50,0x8b,0x5c,0x24,0x48,0xff,0xd3,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x61,0xc3,0x58,0x5f,0x5a,0x8b,0x12,0xe9,0x0b,0xff,0xff,0xff]
# 每三个数为一组
shellcode= [0]*352
for i in range(0,len(src),3):
shellcode[(i//3)*4+3] = src[i+2]&0x3f
shellcode[(i//3)*4+2] = ((src[i+2]>>6)&0x03) | (((src[i+1]&0x0f)<<2)&0xff)
shellcode[(i // 3) * 4 + 1] = ((src[i+1]>>4)&0x0f) | (((src[i]&0x03)<<4)&0xff)
shellcode[(i // 3) * 4 ] = (src[i]>>2)&0x3f
shellcode[(i//3)*4+3] = table.index(shellcode[(i//3)*4+3])
shellcode[(i // 3) * 4 + 2] = table.index(shellcode[(i//3)*4+2])
shellcode[(i // 3) * 4 + 1] = table.index(shellcode[(i // 3) * 4 + 1])
shellcode[(i // 3) * 4] = table.index(shellcode[(i // 3) * 4 ])
for i in range(len(shellcode)):
print(chr(shellcode[i]),end="")
YPxoTHcmBzPSZItSMItSDItSFItyKA+3SiYz/zPArDxhfAIsIMHPDQP44vBSV4tSEItCPAPCi0B4hcAPhL4AAAADwlCLSBiLWCAD2oP5AA+EqQAAAEmLNIsD8jP/M8Cswc8NA/g6xHX0A3wkBDt8JAx12TP/M8mDwlAPtgQKwc8NA/hBg/kOdfHBzw1XM/8zyYtUJDxSD7YcDrhnZmZm9+vR+ovCwegfA8KNBIAr2FoPtgQKK8PBzw0D+EGD+Q511MHPDTs8JHQWaCVzAACLxGhubwAAVFCLXCRI/9PrFGglcwAAi8RoeWVzAFRQi1wkSP/TWFhYWFhYWFhYYcNYX1qLEukL////

向程序之中输入这串字符串就到达了下部分的输入flag

image-20220415183207776

代码分析2

这个部分的函数并不能直接得到,它是将上部分输入的shellcode的base加密的结果写入内存之中,并将这部分数据解析为函数来运行

分配内存空间生成函数

下一部分按照我们输入的shellcode进行base加密(第一次加密)之后的元素,并且将加密的这个结果写入这个空间之中,通过xref这个写入的数组Src我们能够得到

image-20220415183626210

所以写入的数据是:

1
0x60,0xfc,0x68,0x4c,0x77,0x26,0x07,0x33,0xd2,0x64,0x8b,0x52,0x30,0x8b,0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x33,0xff,0x33,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x03,0xf8,0xe2,0xf0,0x52,0x57,0x8b,0x52,0x10,0x8b,0x42,0x3c,0x03,0xc2,0x8b,0x40,0x78,0x85,0xc0,0x0f,0x84,0xbe,0x00,0x00,0x00,0x03,0xc2,0x50,0x8b,0x48,0x18,0x8b,0x58,0x20,0x03,0xda,0x83,0xf9,0x00,0x0f,0x84,0xa9,0x00,0x00,0x00,0x49,0x8b,0x34,0x8b,0x03,0xf2,0x33,0xff,0x33,0xc0,0xac,0xc1,0xcf,0x0d,0x03,0xf8,0x3a,0xc4,0x75,0xf4,0x03,0x7c,0x24,0x04,0x3b,0x7c,0x24,0x0c,0x75,0xd9,0x33,0xff,0x33,0xc9,0x83,0xc2,0x50,0x0f,0xb6,0x04,0x0a,0xc1,0xcf,0x0d,0x03,0xf8,0x41,0x83,0xf9,0x0e,0x75,0xf1,0xc1,0xcf,0x0d,0x57,0x33,0xff,0x33,0xc9,0x8b,0x54,0x24,0x3c,0x52,0x0f,0xb6,0x1c,0x0e,0xb8,0x67,0x66,0x66,0x66,0xf7,0xeb,0xd1,0xfa,0x8b,0xc2,0xc1,0xe8,0x1f,0x03,0xc2,0x8d,0x04,0x80,0x2b,0xd8,0x5a,0x0f,0xb6,0x04,0x0a,0x2b,0xc3,0xc1,0xcf,0x0d,0x03,0xf8,0x41,0x83,0xf9,0x0e,0x75,0xd4,0xc1,0xcf,0x0d,0x3b,0x3c,0x24,0x74,0x16,0x68,0x25,0x73,0x00,0x00,0x8b,0xc4,0x68,0x6e,0x6f,0x00,0x00,0x54,0x50,0x8b,0x5c,0x24,0x48,0xff,0xd3,0xeb,0x14,0x68,0x25,0x73,0x00,0x00,0x8b,0xc4,0x68,0x79,0x65,0x73,0x00,0x54,0x50,0x8b,0x5c,0x24,0x48,0xff,0xd3,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x61,0xc3,0x58,0x5f,0x5a,0x8b,0x12,0xe9,0x0b,0xff,0xff,0xff

利用010生成文件得到代码

将上面这些16进制数据放入010之中,保存为16进制文件,再用ida32打开文件,打开之后,将其声明一下函数,f5反编译,就得到

image-20220415190525034

根据输入的flag参数定位到关键代码的位置,分析逻辑

  • flag和v17的输入进行相同轮数的操作,操作相似,只是flag中加入了v12的某项值

  • 每轮flag和v17加密的结果都要相同,说明flag的每个数都要比v17的每个数大v12[j]%5,这样每轮之中flag减去v12[j]%5,运算结果就相等了

  • 我们需要得到v17和v12这两个数组

image-20220415191447782

动态调试得到数据

使用动态调试的方式得到输入v17和v12,调试程序到图中所示位置(call的那个函数就是程序运行中初始化得到的函数)

image-20220415194339948

进入这个call的程序之中,对比我们之前反编译得到的该函数(ida),知道该函数就是我们要找到的这个函数,可以结合ida之中的反编译和汇编代码来分析代码,定位到我们需要的数据的位置

image-20220415194621421

向下调试,根据循环和移位的特征运算来定位

通过特征代码 移位运算ror和com+jnz定位到v17

image-20220415195511967

定位到v17的数据是: is program cannot be run in DOS mode(我们实际上只需要14位的数据)

image-20220415195538685

向下走在下一个循环之中定位到v12 :LoadLibraryExA

image-20220415200128273

解密得flag

动态调试的数据以及第二部分代码的分析,我们能够得到第二次输入的flag的数据,根据最后的提示,将第一部分的输入和第二部分的输入结合在一起然后md5散列就能够得到我们要的HFCTF{}

解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import hashlib
flag = ""
code = "is program cannot be run in DOS mode"
key = "LoadLibraryExA"
for i in range(14):
flag+=chr(ord(code[i])+ord(key[i])%5)
print(flag)
shellcode = "YPxoTHcmBzPSZItSMItSDItSFItyKA+3SiYz/zPArDxhfAIsIMHPDQP44vBSV4tSEItCPAPCi0B4hcAPhL4AAAADwlCLSBiLWCAD2oP5AA+EqQAAAEmLNIsD8jP/M8Cswc8NA/g6xHX0A3wkBDt8JAx12TP/M8mDwlAPtgQKwc8NA/hBg/kOdfHBzw1XM/8zyYtUJDxSD7YcDrhnZmZm9+vR+ovCwegfA8KNBIAr2FoPtgQKK8PBzw0D+EGD+Q511MHPDTs8JHQWaCVzAACLxGhubwAAVFCLXCRI/9PrFGglcwAAi8RoeWVzAFRQi1wkSP/TWFhYWFhYWFhYYcNYX1qLEukL////"
flag = shellcode+flag
hl = hashlib.md5()
hl.update(flag.encode("utf-8"))
print("HFCTF{"+hl.hexdigest()+"}")
jt"psojvcq!gan
HFCTF{2b794e95022f2fe46106c21bbf57a755}

image-20220415201009353

最后将这两个结果拼接一下,并且再md5一下就能得到最后的结果了

HFCTF{2B794E95022F2FE46106C21BBF57A755}

image-20220415201230903

RITCTF_SOUP

用ida打开,将对比的字符串,每两个数一组,写成数组的形式,作为密文

用动态调试的方法,得到RC4的密钥是 soup,上解密脚本解密

RC4的解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include<stdio.h>

/*
RC4初始化函数
*/
void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len_k)
{
int i = 0, j = 0;
char k[256] = { 0 };
unsigned char tmp = 0;
for (i = 0; i < 256; i++) {
s[i] = i;
k[i] = key[i % Len_k];
}
for (i = 0; i < 256; i++) {
j = (j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}

/*
RC4加解密函数
unsigned char* Data 加解密的数据
unsigned long Len_D 加解密数据的长度
unsigned char* key 密钥
unsigned long Len_k 密钥长度
*/
void rc4_crypt(unsigned char* Data, unsigned long Len_D, unsigned char* key, unsigned long Len_k) //加解密
{
unsigned char s[256];
rc4_init(s, key, Len_k);
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for (k = 0; k < Len_D; k++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
t = (s[i] + s[j]) % 256;
Data[k] = Data[k] ^ s[t];
}
}
int main()
{
//字符串密钥
unsigned char key[] = "soup";
unsigned long key_len = sizeof(key) - 1;
//数组密钥
//unsigned char key[] = {};
//unsigned long key_len = sizeof(key);

//加解密数据
unsigned char data[] = { 0x85,0x5E,0x6E,0xAD,0x05,0x7B,0x46,0xA9,0xD7,0x5F,0x3E,0x07,0x2F,0x35,0x04,0x38 };
//加解密
rc4_crypt(data, sizeof(data), key, key_len);

for (int i = 0; i < sizeof(data); i++)
{
printf("%c", data[i]);
}
printf("\n");
return 0;
}
得到的flag是:BR0CC0L1_CH3DD@R

提交的flag是 RS{BR0CC0L1_CH3DD@R}