304号测试--部分函数分析(1)

Posted by SGQ on April 8, 2020

handler函数:

汇编代码

; void handler(int)
handler proc near
; __unwind {
lea     rax, unk_202014
mov     dword ptr [rax], 1   //令unk_202014 = 1
retn
; } // starts at BC0
handler endp


伪代码

void handler()
{
  unk_202014 = 1;
}

函数分析

令unk_202014 = 1,unk_202014是什么? 后续接着分析 。


signal函数:

汇编代码

; Attributes: thunk

; __sighandler_t signal(int sig, __sighandler_t handler)
signal proc near
jmp     cs:signal_ptr
signal endp

伪代码


__sighandler_t signal(int sig, __sighandler_t handler)
{
  return signal(sig, handler);
}

函数分析

signal(2, (__sighandler_t)handler);

signal为系统函数。

signal(参数1,参数2);

参数1:我们要进行处理的信号。

参数2:我们处理的方式(是系统默认还是忽略还是捕获)。

signal内部时, signal把信号做为参数传递给handler信号处理函数,接着 signal函数返回指针, 并且又指向信号处理函数, 就开始执行它。

当接收到一个类型为sig的信号时,就执行handler 所指定的函数。2是传递给它的唯一参数。执行了signal()调用后,进程只要接收到类型为sig的信号,不管其正在执行程序的哪一部分,就立即执行handler()函数。当handler()函数执行结束后,控制权返回进程被中断的那一点继续执行。


sub_CE0函数

知识点

1.fopen函数是在当前目录下打开一个文件,其调用的一般形式为:

文件指针名=fopen(文件名,使用文件方式);

eg:fp=fopen("a1","rb+");

“文件指针名”必须是被说明为FILE 类型的指针变量;

 “文件名”是被打开文件的文件名;

 “使用文件方式”是指文件的类型和操作要求;

“文件名”是字符串常量或字符数组。

  rb表示只读,rb+表示读写

2.fseek()

功 能: 重定位流上的文件指针

用 法: int fseek(FILE * stream, long offset, int fromwhere);

描 述: 函数设置文件指针stream的位置.如果执行成功,stream将指向以fromwhere为基准,偏移offset个字节的位置.

如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。

返回值: 成功,返回0,否则返回其他值。

第三个参数设定从文件的哪里开始偏移,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET

SEEK_SET: 文件开头
SEEK_CUR: 当前位置
SEEK_END: 文件结尾

其中SEEK_SET,SEEK_CUR和SEEK_END和依次为0,1和2.

简言之:

fseek(fp,100L,0);把fp指针移动到离文件开头100字节处;
fseek(fp,100L,1);把fp指针移动到离文件当前位置100字节处;
fseek(fp,-100L,2);把fp指针退回到离文件结尾100字节处。

3.ftell()

用于得到文件位置指针当前位置相对于文件首的偏移字节数。

ftell(fp);利用函数 ftell() 也能方便地知道一个文件的长。

如以下语句序列:fseek(fp, 0L,SEEK_END); len =ftell(fp);

首先将文件的当前位置移到文件的末尾,然后调用函数ftell()获得当前位置相对于文件首的位移,该位移值等于文件所含字节数。

4.memset()

memset是计算机中C/C++语言初始化函数。作用是将某一块内存中的内容全部设置为指定的值, 这个函数通常为新申请的内存做初始化工作。


void * memset(void * s, int ch, size_t n);

函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。

memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法   。

memset()函数原型是extern void * memset(void * buffer, int c, int count) buffer:为指针或是数组,c:是赋给buffer的值,count:是buffer的长度.

5.fread()

函数声明:size_t fread(void * ptr, size_t size, size_t nmemb, FILE * stream) 

函数作用:从给定流 stream 读取数据到 ptr 所指向的数组中。

参数:

ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
size -- 这是要读取的每个元素的大小,以字节为单位。
nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。

6._mm_storeu_si128函数

功能是可以存储128位的数据。将逗号后的__m128i 变量的值存储到&unk_202018 + 4096所指定的变量中去。

7._mm_unpacklo_epi64()函数

返回一个_m128i的寄存器。

8.memcpy函数:

功能

memcpy指的是C和C++使用的内存拷贝函数,函数原型为
void * memcpy(void * destin, void * source, unsigned n);

函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中。

参数

destin-- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
source-- 指向要复制的数据源,类型强制转换为 void* 指针。
n-- 要被复制的字节数。

返回值

   该函数返回一个指向目标存储区destin的指针。

9._QWORD是一种无符号整数类型。

10.0LL long long类型的0


伪代码

enter description here

汇编代码


总结:

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

通过输入命令行,获取字节码文件的信息,并传入处理函数。在myvm中其实就是将文件送入sub_CE0()中,将字节码字段加载到 内存空间的正文段。

sub_CE0()主要完成的是初始化虚拟机的操作。读取字节码内容。


参考链接:

linux下signal()函数超详细介绍

fseek() 函数用法

C语言文件常用操作