Tan's Blog.

304Challenge:代码分析1

字数统计: 814阅读时长: 3 min
2019/04/23 Share

main函数

今天对main函数的汇编代码结合伪代码进行分析,使用F5大法生成伪代码。

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
char *v4; // rbx
int v5; // eax

if ( a4 == 2 )
{
signal(2, (__sighandler_t)handler);
v4 = sub_CE0(a1[1]);
unk_202014 = 1;
while ( 1 )
{
v5 = sub_E90(v4);
if ( v5 )
break;
if ( !unk_202014 )
goto LABEL_8;
}
if ( v5 == 2 )
puts("Illegal Instruction");
LABEL_8:
nullsub_1(v4);
}
else
{
fprintf(stderr, "Usage: %s <myvm program>\n", *a1, a3);
}
return 0LL;

首先对栈进行初始化操作,然后判断a4(edi)==2?
不成立就进行print操作,输出file流文件,然后跳C3D出栈。
成立的话会调用一个signal函数,查询了一下signal(a1,a2),a1为要进行处理的信号,这里为2;a2为处理方式,一般来说处理方式一般有三种:
SIG_IGN 忽略该信号
SIG_DFL 恢复对信号的系统默认处理
sighandler_t 执行handler函数
在此处就需要执行handler函数,使用handler处理信号量2.
令rdi=rbx+8,调用sub_CE0

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
FILE *v1; // rax
FILE *v2; // rbx
__int64 v3; // r15
void *v4; // r14
char *v5; // rbx

v1 = fopen(a1, "rb");
v2 = v1;
if ( !v1 )
return 0LL;
fseek(v1, 0LL, 2);
v3 = ftell(v2);
fseek(v2, 0LL, 0);
v4 = malloc(0x10000uLL);
memset(v4, 0, 0x10000uLL);
fread(v4, 1uLL, v3, v2);
fclose(v2);
_mm_storeu_si128(
(__m128i *)&unk_202018 + 4096,
_mm_unpacklo_epi64((__m128i)(unsigned __int64)&unk_202018, (__m128i)((unsigned __int64)&unk_202018 + 0x8000)));
memcpy(&unk_202018, v4, 0x10000uLL);
_mm_storeu_si128((__m128i *)&unk_202018 + 4097, (__m128i)0LL);
*(_QWORD *)((char *)&unk_202018 + 65566) = 0LL;
*((_WORD *)&unk_202018 + 32785) = 32764;
*((_QWORD *)&unk_202018 + 8197) = 0LL;
v5 = (char *)&unk_202018 + 0x10000;
free(v4);
return v5;

sub_CE0里先打开a1文件,如果是空就可以直接返回了。不为空,就定位文件头和尾,v3是文件首的偏移字节数,再动态分配一个内存,memset对内存初始化操作。读取文件中的数据到新内存中,关闭文件流。之后一大段SSE指令,把一些内容放到&unk_202018中,又将&unk_202018 + 65536赋值给v5.释放内存空间,返回。

总结

在分析过程中遇到几个函数,进行整理。
(1)signal(a1,a2)这个在之前分析代码时写过。
(2)int fseek(FILE stream, long offset, int fromwhere)把fp的文件读写位置指针移到指定的位置.
SEEK_SET 0 文件开头
SEEK_CUR 1 文件当前位置
SEEK_END 2 文件末尾
(3)long ftell(FILE
fp) 得到流式文件的当前读写位置,其返回值是当前读写位置偏离文件头部的字节数
(4)void malloc(size_t size) 用于申请一块连续的指定大小的内存块区域,以void 类型返回分配的内存区域地址
(5)void memset(void s,int c,size_t n) 将已开辟内存空间 s 的首 n 个字节的值设为值 c。
(6)size_t fread( void buffer, size_t size, size_t count, FILE stream )

buffer 是读取的数据存放的内存的指针
size 是每次读取的字节数
count 是读取次数
stream 是要读取的文件的指针

(7) void _mm_storeu_si128( m128i * p, m128i a) 可存储128位数据,将__m128i 变量a的值存储到p所指定的变量中去

(8)_mm_unpacklo_epi64 (m128i a, m128i b) 返回一个m128i的寄存器,它将寄存器a和寄存器b的低64bit数以64bit为单位交织在一块。

(9)void memcpy(void str1, const void * str2, size_t n) 从存储区 str2 复制 n 个字符到存储区 str1

由于代码量比较大,今天只分析一小部分,明天继续分析。

CATALOG
  1. 1. main函数
  2. 2. 总结