首页
社区
课程
招聘
[求助]这是反调试、数据存储的、没完全看懂
发表于: 2013-10-18 16:28 7522

[求助]这是反调试、数据存储的、没完全看懂

2013-10-18 16:28
7522
static void __stdcall KeyStorage_Set(unsigned char Index, void *Value)
{
  __asm {
    xor eax, eax
      mov al, Index
      mov edx, Value
      call skip_key_seh1
      mov  ecx, [esp+0x0c]
    push ebx
      mov  dword ptr [ecx], 0x10017
      mov  ebx, [ecx+0xB0]
    inc ebx
      shl ebx, 2
      mov  eax, [ecx+0xA8]
    mov  [ecx+ebx], eax
      inc  dword ptr [ecx+0x0b8]
    inc  dword ptr [ecx+0x0b8]
    xor  eax, eax
      mov  [ecx+20], eax
      mov  [ecx+24], eax
      pop ebx
      ret
skip_key_seh1:
    xor      ecx,ecx
      push dword ptr fs:[ecx]
    mov  dword ptr fs:[ecx],esp
      inc  byte ptr [ecx]
    nop
      nop
      pop  dword ptr fs:[ecx]
    add  esp,4
  }
}

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
免费 0
支持
分享
最新回复 (9)
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
call skip_key_seh1,没有什么判断直接CALL
中间代码没执行吧
mov al, Index
mov edx, Value
CALL *******
pop  dword ptr fs:[ecx]
add  esp,4

push2个, pop 2个

不知道是不是这样
2013-10-18 17:09
0
雪    币: 239
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
运用了异常处理,call skip_key_seh1将异常处理的地址入栈,也就是下一句,然后到skip_key_seh1,push前一个EXCEPTION_REGISTRATION结构,然后将当前的栈顶(新的EXCEPTION_REGISTRATION结构)赋给fs:[0],然后inc dword ptr[ecx]引发异常,调到上面call的下一句执行
2013-10-18 18:41
0
雪    币: 276
活跃值: (26)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4

Context异常结构自己看吧。

这段代码总的来说,就是:
if(没有调试器)
   根据函数 索引参数 将 指针参数 赋值给指定参数
2013-10-18 19:35
0
雪    币: 276
活跃值: (26)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
这个做等价符: <==>

mov  ecx, [esp+0x0c] <==> ecx = offset Context

mov  dword ptr [ecx], 0x10017 <==> Context.ContextFlags = 0x10017

------------------------------
mov  ebx, [ecx+0xB0]   |
inc ebx                          |
shl ebx, 2                      | <==> (ecx+4)[Index] = Value   这几句最重要,上面都是在为此做准备
mov  eax, [ecx+0xA8]   |
mov  [ecx+ebx], eax     |
------------------------------

------------------------------------
inc  dword ptr [ecx+0x0b8]  |
inc  dword ptr [ecx+0x0b8]  | <==> eip += 2
------------------------------------

其他没啥重要的,
2013-10-18 19:48
0
雪    币: 72
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
楼上的、我对你的崇拜犹如滔滔江水绵绵不绝、加我Q吧:31990839
2013-10-18 20:16
0
雪    币: 72
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
能再解释的详细些就好了、这个函数如何来使用、还有一个对应的取的函数、和这个差不多的!
2013-10-18 20:40
0
雪    币: 622
活跃值: (294)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
8
typedef struct _CONTEXT {

    DWORD ContextFlags;
    DWORD   Dr0;
    DWORD   Dr1;
    DWORD   Dr2;
    DWORD   Dr3;
    DWORD   Dr6;
    DWORD   Dr7;
    FLOATING_SAVE_AREA FloatSave;
{
    DWORD   ControlWord;
    DWORD   StatusWord;
    DWORD   TagWord;
    DWORD   ErrorOffset;
    DWORD   ErrorSelector;
    DWORD   DataOffset;
    DWORD   DataSelector;
    BYTE    RegisterArea[80];
    DWORD   Cr0NpxState;
}
    DWORD   SegGs;
    DWORD   SegFs;
    DWORD   SegEs;
    DWORD   SegDs;
    DWORD   Edi;
    DWORD   Esi;
    DWORD   Ebx;
    DWORD   Edx;
    DWORD   Ecx;
    DWORD   Eax;
    DWORD   Ebp;
    DWORD   Eip;
    DWORD   SegCs;              // MUST BE SANITIZED
    DWORD   EFlags;             // MUST BE SANITIZED
    DWORD   Esp;
    DWORD   SegSs;
    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];

} CONTEXT;

参考CONTEXT结构的数据成员,以及你说还有一个类似的取操作的函数,同时结合这个函数的命名,说明这一组函数应该是用于使用调试寄存器存取key数值的,以达到反调试的作用。由于调试寄存器使用常规模式是无法访问的,所以必须制造异常,在异常处理中才可以随意读取改写。

static void __stdcall KeyStorage_Set(unsigned char Index, void *Value)
{
  __asm {
    xor eax, eax
      mov al, Index
      mov edx, Value
      call skip_key_seh1
/*
这个call指令相当于两步
push 下一条指令的地址,也就是mov ecx,[esp+0x0c]这条指令的地址
jmp skip_key_seh1
*/
      mov  ecx, [esp+0x0c]
/*此时ecx指向CONTEXT结构*/
    push ebx
      mov  dword ptr [ecx], 0x10017
      mov  ebx, [ecx+0xB0]
/*ebx内容变为CONTEXT.eax,即前面代码中eax获得的参数Index的数值*/
    inc ebx
      shl ebx, 2
/*由于DWORD数据类型是4字节的,所以这里要Index*4,以便实现数据对齐*/
      mov  eax, [ecx+0xA8]
/*这里eax变为CONTEXT.edx,即前面代码中edx获得的参数Value的数值*/
    mov  [ecx+ebx], eax
/*这里便是修改CONTEXT结构里面的数据成员了,由于DR之后的寄存器大部分都很容易被改写,或者修改了会导致程序出错,所以较为安全的可使用的寄存器便只有DR0~7了*/
      inc  dword ptr [ecx+0x0b8]
    inc  dword ptr [ecx+0x0b8]
    xor  eax, eax
      mov  [ecx+20], eax
      mov  [ecx+24], eax
      pop ebx
      ret
skip_key_seh1:
    xor      ecx,ecx
      push dword ptr fs:[ecx]
    mov  dword ptr fs:[ecx],esp
/*
结合上面call指令的作用,一直到上面的mov  dword ptr fs:[ecx],esp
实际上完成了一次异常处理的构建,指明下一次异常由指定的异常处理代码来处理,这里就是指向上面call指令的下一句代码位置*/
      inc  byte ptr [ecx]
/*
由于上面有xor ecx,ecx的语句,所以此处ecx实际上是0,所以这一句代码试图将处于线形地址0位置的dword数据+1,实际上是为了引发异常,因为那一块的内存在用户模式下是不允许访问的*/
    nop
      nop
      pop  dword ptr fs:[ecx]
/*
这里是拆除前面构建的异常以防影响到后面其他代码中引发的异常处理机制*/
    add  esp,4
  }
}
2013-10-18 22:24
0
雪    币: 124
活跃值: (429)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
恍然大悟,到底怎么实现context的修改
2013-10-19 09:28
0
雪    币: 72
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
KeyStorage_Set(1, (void*)1)

int = (int)KeyStorage_Get(1)

为什么VS在debug下没问题、在release下就不行了呢????
2013-10-19 18:40
0
游客
登录 | 注册 方可回帖
返回
//