加密与解密第一篇笔记

note about chapter 1

1.1.2

逆向工程定义:

  • 软件使用限制的去除或者软件功能的添加。
  • 软件源代码的再获得。
  • 硬件的复制和模拟。

动态分析注意点:

  • 对软件进行粗跟踪
  • 对关键部分进行细跟踪

1.3.2 SysWOW64与System32

64位系统如何兼容32位程序的:

System32存放64位映像文件,SysWOW63存放32位系统文件。

32位程序加载时,WOW64建立32位ntdll.dll所要求的启动环境,将CPU模式切换至32位,并开始执行32位加载器,就如同该进程运行在原生的32位系统上一样。

1.3.4 虚拟内存相关

虚拟内存的过程:

  1. 一个程序启动,系统创建一个进程,并给该进程分配2GB虚拟地址;
  2. 虚拟内存管理器讲应用程序的指令映射到那个程序的虚拟地址中某个位置,并给当前需要的代码读入物理内存;
  3. 如果使用了DLL,DLL也会被映射到虚拟地址空间中,在需要的时候才会被读入物理内存;
  4. 其他项目的空间是从物理内存中分配的,并被映射到虚拟地址空间中;
  5. 应用程序通过使用其虚拟地址空间中的地址开始执行。然后,虚拟内存管理器把每次内存访问映射到物理空间;

note about chapter 2

基本操作

alt+f9:进入程序领空;

ctrl+f9:运行到下一个ret;

有个小题目,认识下GetDlgItemTextA这个函数即可。

2.1.4 常用断点

int3断点

断点处的指令被替换成了0xCC,调试器捕捉该异常,运行到这里后恢复原有指令。

防止该断点的方法,检测调用的api是否被改成了0xCC:

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
29
30
31
32
33
#include <windows.h>

BOOL IsCC();


int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{

if( IsCC() )
MessageBox(NULL,TEXT ("Found Debug!"),TEXT ("OK"),MB_ICONEXCLAMATION);
else
MessageBox(NULL,TEXT ("No Debug!"),TEXT ("Error"),MB_ICONEXCLAMATION);

return 0;
}

//////////////////////////////////////////////////////////////////////



BOOL IsCC()
{
FARPROC Uaddr ;
BYTE Mark = 0;P
(FARPROC&) Uaddr =GetProcAddress ( LoadLibrary("user32.dll"),"MessageBoxA");
Mark = *((BYTE*)Uaddr); // 取MessageBoxA函数第一字节
if(Mark ==0xCC) // 如该字节为CC,则认为MessageBoxA函数被下断
return TRUE;
else
return FALSE;

}

躲避方法,断点设在被检测指令的下一条指令就行了。

硬件断点

一共可以设置四个硬件断点。

原理:将被设置断点的指令的地址存储在DR0-DR3寄存器中的一个,然后再DR7寄存器中设置相应的控制位。

Olldbg F4的原理就是设置一个硬件断点,运行到指定EIP后删除该硬件断点。

内存断点

内存访问断点或者内存写入断点。

原理:对所设置的地址赋予不可写/访问的权限,这样方法/写时就会造成异常,Ollydbg就会捕获这种异常,并比较是否为断点地址,是则中断。

该断点因为每次遇到上述异常都会进行判断是否为断点地址,所以会造成程序运行速度变慢。

由于内存执行,一定会有内存访问,所以可以设置内存访问断点避开对0xCC指令的检查。

内存访问一次性断点

当想捕捉调用或返回某个模块,可以使用该类断点,在M页面F2。

消息断点

条件断点

  1. 按照寄存器条件设置断点;
  2. 按照存储器条件设置断点;

条件记录断点

2.1.6

Run Trace的使用。

note about chapter 3

3.3.16

提供了一个定位.idata中输入表的脚本:

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
29
#coding=utf-8
##《加密与解密》第四版

def GetImportSeg():
ea=FirstSeg()
next=ea
count=0

while next != BADADDR: #判断是否为".idata"段
next=NextSeg(next)
name=SegName(next)
if name[0:6]=='.idata':
break
return next

def main():
BytePtr=SegStart(GetImportSeg()) #确定idata段VA
EndImports=SegEnd(BytePtr)
print('\n Parsing import table...')
while BytePtr<EndImports:
if LineA(BytePtr,1):
print( '__'+LineA(BytePtr,1)+'__')
if Name(BytePtr):
print(Name(BytePtr)+'\n') #显示当前地址的函数名
BytePtr=NextAddr(BytePtr)
print('Import table parsing complete\n')

if __name__=='__main__':
main()

一种SMC的解密:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <idc.idc>
static decrypt(from, size, key ) {
auto i, x;
for ( i=0; i < size; i=i+1 ) {
x = Byte(from);
x = (x^key);
PatchByte(from,x);
from = from + 1;
}
Message("\n" + "Decrypt Complete\n");
}