能力值:
( 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个
不知道是不是这样
|
能力值:
( LV2,RANK:10 )
|
-
-
3 楼
运用了异常处理,call skip_key_seh1将异常处理的地址入栈,也就是下一句,然后到skip_key_seh1,push前一个EXCEPTION_REGISTRATION结构,然后将当前的栈顶(新的EXCEPTION_REGISTRATION结构)赋给fs:[0],然后inc dword ptr[ecx]引发异常,调到上面call的下一句执行
|
能力值:
( LV3,RANK:20 )
|
-
-
4 楼
Context异常结构自己看吧。
这段代码总的来说,就是:
if(没有调试器)
根据函数 索引参数 将 指针参数 赋值给指定参数
|
能力值:
( 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
------------------------------------
其他没啥重要的,
|
能力值:
( LV2,RANK:10 )
|
-
-
6 楼
楼上的、我对你的崇拜犹如滔滔江水绵绵不绝、加我Q吧:31990839
|
能力值:
( LV2,RANK:10 )
|
-
-
7 楼
|
能力值:
( 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
}
}
|
能力值:
( LV4,RANK:50 )
|
-
-
9 楼
恍然大悟,到底怎么实现context的修改
|
能力值:
( LV2,RANK:10 )
|
-
-
10 楼
KeyStorage_Set(1, (void*)1)
int = (int)KeyStorage_Get(1)
为什么VS在debug下没问题、在release下就不行了呢????
|
|
|