1.小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
2.MD5加密:单向算法,只能从字符串计算出MD5值,不能逆向计算出源代码(因为并非一一对应的,可能有多个源码对应一个MD5)。MD5的碰撞。应用:RAR密码
3.静态的数据(RAR,图片等)加密后一般无法破解。
4.破解的方法:①.找出加密原理 ②.绕过判断机制(低级)
5.RSA加密:双密钥算法(公钥和私钥,不能互推),涉及素数,取模计算(将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥)。公钥只用来加密(一般是公开的),私钥只用来解密(关键,不公开),只有知道私钥才能解密,否则即使是加密者也无法解密。应用(广泛):数字签名,email加密。
6.注册码的生成方法之一:EXE内只有公钥及N,作者本人有私钥,用户的mac地址作为机器特征码,
m' =RSA(mac,公钥)发送给作者,作者先收取mac地址 = RSA(m',私钥),计算注册码 sn =RSA(mac,私钥)返回给用户,软件再对sn进行计算y = RSA(sn,公钥),if( y==mac ) Success!
破解思路:替换EXE内的公钥为自己知道的一组密钥,以此计算出一组注册码给修改过的软件校验。
7.机器语言不能直接删除,否则会使后面的地址全部往上填充进来,这样会影响后面的涉及地址跳转的操作。方法:①把需要修改的操作机器码都改成 90 (nop—No Operation)
②改成jump+ 地址,跳转到验证完的地址
8.修改exe文件:010Editor(只能查看16进制),QuickView(可以查看16进制和汇编代码)
QuickViewF7搜索,F2在16位汇编和32位汇编切换,F3撤销,
Tab在机器码与汇编码间切换,Alt+F9保存,F1帮助
9.寄存器ds只能赋值为另一个寄存器的值而不能直接赋值为常数
10.data代表字符串abc的段地址,而offset abc是abc的偏移地址,段地址:偏移地址 ->组成一个完整的地址
11.Build == compile +link
assemble == compile : asm-->obj
link : obj-->exe
12.表示一个十六进制常数时,必须用数字开头(如果是字母就添0)
13.C语言数字类型的对应关系:
unsignedchar = byte(8位) db(definebyte)
unsignedshort int = word(16位) dw
unsignedlong int = double word(32位) dd
14.定义一个char的变量a:
a db 12h ; unsigned char a = 0x12
15.小端模式(Little Endian):与书写习惯相反,比如存放一个变量long long a = 0x12345678h
变量的地址为1000,则连续地址存放的数据: 1000:78h 1001:56h 1002:34h 1003:12h
意义:a仍为long long,定义char b,若执行b =a,则a会自动强制转换为8位的char,小端模式使其只取首地址抛弃之后多余的地址的值
即只将地址1000里的78h赋值给b,亦即把最低位开始的值赋值给b,符合常规的思维习惯
16.char->unsignedint ,假定unsigned int 是16位(如TC环境)
若原先的8是符号数,则需要进行符号扩充,规则:左边补上的位值 = 原数的最高位(即正数补0,负数补1)(正数不变)
1111 1111 -> 11111111 1111 1111
char 的-1 -> unsigned int 的 -1
符号扩充只跟被扩充数的类型有关(即只要它是符号数就必须进行符号扩充),与扩充以后的目标类型无关(即不管它是有符号还是非符号)
17.unsiged char ->int / unsigned int
规则:左侧一律补0
18.小数在内存中的保存:如 float x = 127.375(四个字节)
01000010 1111111011000000 00000000
0 1000010 1 1111110 1100000000000000
符号 偏置指数(8位) 尾数(23位)
偏置指数 = 133
则实际指数 = 133-127 = 6
对尾数的处理:先在前面添加一个1凑够24位,并且在这个1后添加一个小数点 1.1111110 11000000 00000000
将小数点向后移动6位,变成 1111111.0 11000000 00000000
可得实际数据 127.375 (小数点后第n位的权值为2^-n)
19.console application可以单步往下跟
windows application里面有消息循环,所以通常用单步跟踪无法到达注册码判断的位置
所以必须要有切入点,即找出注册码判断时可能调用的判断函数
一般是MessageBoxA(弹出消息框),CreateWindow(),ShowWindow(),【DestroyWindow()】(一般离判断最近)
20.常用拦截API:CreateFileA()与打开文件有关(之后又ReadFile()读取文件内容)
RegCreateKey(),RegOpenKey()
21.filemon可以监视打开并写入到什么文件;regmon可以监视注册表的写入; autoruns 可以观察开机运行程序
22.8086(16位)共有14个寄存器,每个寄存器都是16位(决定地址位数和int位数(宽度)):
AX,BX,CX,DX,(通用寄存器,算数运算,位运算)
SP,BP,SI,DP(用来存放偏移地址)
CS,DS,ES,SS(用来存放段地址),IP(instruction pointer,当前指令的偏移地址),FL(flag,标志寄存器)
23.所有类型的指针大小都等于寄存器大小,因为指针变量需要用一个寄存器来表示。
比如,在16位CPU中,si,di,bx,bp均可以表示一个指针;
32位CPU中,eax,ebx,ecx,edx,esi,edi,ebp,esp均可以表示指针
64位CPU中,rax,rbx,rcx,rdx,rsi,rdi,rbp,rsp均可以表示指针
24.32位CPU的地址最大值(寻址范围)为2^32-1 B,即3.多GB(即32位系统所支持的最大内存)
25.地址 = 段(首)地址:偏移地址(把一个物理地址用两个16位寄存器分别存储)
如一个物理地址 12398h=1234:0058=1235:0048=1236:0038=1230:0098
26.段首地址最后一位必须等于0
27.32位内存也需要分段,一是便于管理,二是段具有自己的属性,能够对某一段内存设置属性(如只读)
28.GDT表:
gdtr = gdt的首地址
29.AX由AH及AL构成,其中AH是高8位,AL是低8位。BX,CX,DX同。
mov ah,98h
mov al,0DEh
30.ds:[esi] 表示在ds指向的段中,取出esi所指的对象
地址 值
31.byteptr 相当于 (char*)强制类型转换(byte一个字节,相当于char), 2000:1000 34h
例如: 2000:1001 12h
movax,2000h 2000:1002 56h
movds,ax 2000:1003 78h
movsi,1000h
mov al,byte ptr ds:[si] ;把ds:[si]指向的数据转换为byte类型后存储到al中,AL=34h(间接寻址)
mov ax,word ptrds:[si] ;AX =1234h
mov eax,dword ptrds:[si] ;eax = 78561234h
其中mov的目的地为寄存器时,byte/word/dword ptr 这三个语句可以省略
因为编译器会进行类型的检查,当检测到mov左边为寄存器时,会自动把右边的数值强制转换为与寄存器的位数对应的类型(al-8位,ax-16位)
32.在程序中引用某个变量,段地址必须用段地址寄存器;而偏移地址可以用寄存器(间接寻址),也可以用常数(直接寻址),或两者的组合(加减法)
33.若两个值相加超过了寄存器的位数,则抛弃高位只取低位
34.一段源程序:
datasegment
abc db1,2,3 ;char[3] = {1,2,3};
xyz dw1234h, 5678h, 9999h
data ends
codesegment
assume cs:code ds:data
mov ah,ds:abc 将abc这样写,该句编译后变成 movah,ds:[0000] ;(相当于把abc加上方括号,即取其偏移地址)
mov ah,ds:[abc] abc本来是变量的名字,用方括号括起来就变成了它的偏移地址,编译后与上一句相同
mov bl,ds:[abc+1] 编译后变成movbl,ds:[0001]
mov bl,ds:abc[1] 编译后变成movbl,ds:[0001] 这里abc[1]并不是数组abc的第一个元素,而是相对于abc的地
址+1的地址
; mov bl,ds:abc+1 虽然编译后同上一句,但是防止混淆应避免这样的写法
movcs,ds:xyz cs = 1234h
movdx,ds:[xyz] cs = 1234h
movsi,ds:xyz[2] si = 5678h
mov di
movah,4Ch
code ends
end
35.控制寄存器:IP,FL
IP: instruction pointer 指令指针,与CS配合起来指向将要执行的下一条指令
即 CS:IP 指向下一条将要执行的指令(32位当然是ECS:EIP)
FL:Flag
状态标志:CF,ZF,SF,OF,AF,PF(后两个较少用)
控制标志:DF,IF,TF
以上9个位都存在于标志寄存器FL中
寄存器FL的长度取决于CPU位数
36.CF:进位标志(carry flag):随时反映当前计算结果是否有进位(或借位)
这里的进位(借位) 指的是对当前 寄存器最高位的更高位进位(或借位)
比如 al是的宽度为8位, 只有计算结果需要用到第九位才叫进位(或借位)
moval,0FFh al = 1111 1111
add al,2 al = 00000001 (FF与2相加产生了进位,CF的状态会立即变为1)
有时也把CF=1称为非符号数的溢出标志(ff+2!=1,相加过程中有一位溢出)
相关指令(用途):
moval,oFFh
add al,2
jc has_carry(段名) (jump if has carry,有进位则跳)
...
has_carry:
....
注:CF也可表示借位标志,当做减法运算产生借位时,也会变成1
37.OF(Overflow Flag)溢出标志(以下情形均为符号数)
溢出有两种情况:两个正数相加的结果是负数,两个负数相加的结果是正数就溢出(一正一负相加不会溢出)
moval,oFFh
add al,2
执行完后 OF=1,CF=1
相关指令jo(jump ifoverflow),jno(jump if not overflow)
38.SF(Sign Flag) = 【运算结果的最高位】
反映当前的运算结果是正的(SF=0)还是负的(SF=1)
相关的指令:js(SF=1时,即有符号则跳),jns(SF=0,无符号则跳)
39.ZF(Zero Flag)零标志
运算结果为0时,ZF=1;否则ZF=0 (应该把ZF的值理解为真和假)
subax,ax ;AX=0,ZF=1
addax,1 ;AX=1,ZF=0
指令:jz(jump ifzero)==je
jnz(jump if not zero)==jne(机器码完全相同,两个指令等价)
原因:
cmpax,bx
jethey_are_equal
实际上cmp指令做的是减法运算,因此ax==bx即差等于零时,ZF=1,je和jz都会执行
但与减法运算sub相比,cmp指令不会改变左侧变量的值
40.AF(Auxiliary Carry Flag):辅助进位标志
记录运算时第五位(二进制的第n位都是右数,且最右边的为第0位)产生的进位或借位值
第五位有进位或借位时,AF=1;否则AF=0
moval,23h
addal,1Fh
41.PF(Parity Flag) 奇偶标志
当运算结果的低八位(即用16进制表示的2位)中"1"的个数为偶数时,PF=1,否则PF=0.
指令:
jp==jpe(jumpif parity even)
jnp==jpo(jumpif parity odd)
42.DF(DirectionFlag):
标志位DF控制字符串操作的方向,当DF=0时为正方向,
DF=1时为反方向.
若源首地址<目标首地址,则复制按反方向
(如右图,左边为源地址,右边为目标地址)
若源首地址>目标首地址,复制按正方向
用指令cld使DF=0,用指令std使DF=1
cld(clear direction,使DF=0,表示正方向)
std(set direction,使DF=1,表示反方向)
43.IF(Interrupt Flag)中断标志:
当IF=1时,允许中断;否则关闭中断.
cli指令使 IF=0 表示关/禁止硬件中断
sti指令使 IF=1 表示开/允许硬件中断
键盘缓冲区 是一个队列(可以理解为一个数组)
charkey[100]
char *p =&key[10]
(时钟中断)
44.
TF(Trace/Trap Flag) 跟踪