304号测试--sub_E90函数分析

Posted by SGQ on April 8, 2020

前言:

最近在忙毕设与复试的内容,304测试暂时没顾上,今天分析了一下sub_E90函数,此函数内容还是挺多的。


知识点:

1.(_DWORD )?

(_DWORD )是强制类型转化,然后在提领指针。

dword是指注册表的键值,每个word为2个字节,dword双字即为4个字节。

结合以上信息可以推出其中一个代码*(_DWORD *)a1 + 11)的理解应为:

从 a1[11] 开始,按DWORD格式取出 四个字节。

2.byte类型

 byte,即字节,由8位的二进制组成,byte类型的数据是8位带符号的二进制数。

byte类型与int类型的区别?

1、类型不一样,byte是字节数据的类型,int是整型数据的类型。

2、占用的字节不一样,byte占用1 个字节,int占用4个字节。

3、大小范围不一样,byte 的大小范围是道-128—127 ,int的大小范围是-2147483648到2147483647。

3.exit(0),_exit(0),exit(1),exit(-1)作用与区别

exit(0):正常运行程序并退出程序。

_exit(0):不能输出结果,未清除I/O缓存,不打印。

exit(1):非正常运行导致退出程序;

 exit(-1):非正常运行导致退出程序,与1类似。

 在main中return v;的效果与exit(v);相同。

伪代码分析


  __int64 __fastcall sub_E90(__int64 *a1)
{
  __int64 *v1; // rbx
  unsigned int v2; // er14
  __int64 v4; // rsi
  unsigned __int64 v5; // rcx
  __int64 v6; // rdx
  _BYTE *v7; // r15
  __int16 v8; // di
  unsigned __int16 v9; // ax
  __int16 v10; // ax
  __int16 v11; // cx
  __int16 v12; // ax
  __int64 v13; // rax
  __int16 v14; // ax
  __int64 v15; // rax
  __int16 v16; // ax
  unsigned __int16 v17; // ax
  __int16 v18; // dx
  unsigned __int16 v19; // ax
  int v20; // eax
  int v21; // ecx
  int v22; // eax
  __int64 v23; // rax

  v1 = a1;                                 //v1指向数组a1
  v2 = 1;
  if ( !*((_DWORD *)a1 + 11) )             //a1[11]为0
  {
    v4 = *a1;                              //v4等于a1[0]
    v5 = a1[1];                            //v5等于a1[1]
    v6 = *((unsigned __int16 *)a1 + 15);   //v6等于a1[15]
    v7 = (_BYTE *)(*a1 + v6);              //v7等于a1[0]+v6,byte型
    if ( (unsigned __int64)v7 >= v5 )      //v7大于v5
LABEL_72:
      exit(-1);                            //非正常运行退出程序
    v8 = v6 + 4;                           
    *((_WORD *)v1 + 15) = v6 + 4;           //v1[15]=v6+4
    v2 = 0;
    switch ( *v7 + 112 )                    //v7+112
    {
      case 0:
        return v2;                          //返回v2
      case 128:
        v11 = *((_WORD *)v1 + (unsigned __int8)v7[2] + 8) + *((_WORD *)v1 + (unsigned __int8)v7[3] + 8); //v11=a1[v7[2]+8]+a1[v7[3]+8]
        goto LABEL_25;                      //执行LABEL_25之后的代码 

      。。。
      。。。
      。。。



}
return v2;
}

总结

sub_E90完成的是将读取的字节码翻译执行。

把这些字节码送入指令执行引擎函数sub_E90中,将字节码指令从虚拟地址0处开始逐条执行,当遇到HALT指令或发生错误时停止。

myvm中sub_E90函数执行的是中间switch那段,用于识别各种机器指令,并执行。

机器指令按照操作数的不同来分,包括双操作数指令(OP DEST,SRC)、单操作数指令(OPDEST)、无操作数指令(op)等3种。由于操作数的不同直接关系到指令指针IP的变化不同,因此R[IP]值的变化将因具体指令的操作数不同而异。

所以switch中的各个case,是各条指令,比如jmp,jz,sub等

具体功能后续再分析。


参考链接:

详解java中的byte类型