CrackMe 001
一直在搞开发,许久没有碰二进制逆向了,今日突然来了兴致,就做了一个入门级的crackme。做题是假
,温习是真。主要借着题目复习一些汇编相关知识点。
首先,打开图片
看到出现错误提示--------->查找所有参考字符串----------->跟踪定位到错误字符串提示处
计算机储存信息基本单元
计算机存储信息的基本单元是位(bit)和字节(byte)。下面是它们及其单位的转换关系:
- 位(bit):计算机中最小的存储单元,只能存储0或1。8个位构成一个字节。
- 字节(byte):通常用于表示存储容量,是计算机中常见的基本存储单位。1字节等于8位。
- 1 字(word)= 2 字节
- 1 双字(dword)= 4 字节
- 1 四字(qword)= 8 字节
常见的存储单位及其转换关系如下:
- 1 字节(byte) = 8 位(bit)
- 1 千字节(KB) = 1024 字节
- 1 兆字节(MB) = 1024 KB
- 1 千兆字节(GB) = 1024 MB
- 1 太字节(TB) = 1024 GB
- 1 拍字节(PB) = 1024 TB
需要注意的是,存储容量的单位通常采用二进制计量单位,即以2的幂为基准进行换算。例如,1 KB = 1024 字节,而不是1000字节。
寄存器
00401E82 . 8D4D C4 lea ecx,dword ptr ss:[ebp-0x3C]
00401E85 . C745 8C E01A4>mov dword ptr ss:[ebp-0x74],Andréna.00401AE0 ; UNICODE "Leider Falsch ! Schau noch mal genau nach ..."
00401E8C . 895D 84 mov dword ptr ss:[ebp-0x7C],ebx
计算机的寄存器是中央处理器(CPU)内部的一种快速存储单元,用于临时存储数据和指令。在不同的CPU架构中,寄存器的类型和数量会有所不同。以下是几种主要的寄存器类型,基于常见的x86架构和一些其他架构的:
通用寄存器
16位模式下,寄存器的大小为16位,如ax
, bx
, cx
, dx
, si
, di
, sp
, bp
。
x86架构(32位)
- EAX(累加寄存器,Accumulator):用于算术运算和I/O操作。
- EBX(基址寄存器,Base):用于基址寻址。
- ECX(计数寄存器,Counter):用于循环计数。
- EDX(数据寄存器,Data):用于I/O操作和乘法/除法指令。
- ESI(源索引寄存器,Source Index):用于字符串操作。
- EDI(目的索引寄存器,Destination Index):用于字符串操作。
- EBP(基址指针寄存器,Base Pointer):用于指向当前栈帧的基址。
- ESP(栈指针寄存器,Stack Pointer):指向栈顶。
x86_64架构(64位)
在x86_64架构中,寄存器的前缀变为R,且有更多的寄存器可用:
- RAX, RBX, RCX, RDX:与32位寄存器类似,用于通用目的。
- RSI, RDI, RBP, RSP:与32位寄存器类似,但扩展为64位。
- R8-R15:额外的通用寄存器。
段寄存器
- CS(代码段寄存器,Code Segment):指向当前代码段。
- DS(数据段寄存器,Data Segment):指向数据段。
- SS(栈段寄存器,Stack Segment):指向栈段。
- ES(附加段寄存器,Extra Segment):额外的数据段寄存器。
- FS(附加段寄存器,Extra Segment):用于特殊数据。
- GS(附加段寄存器,Extra Segment):用于特殊数据。
指令指针寄存器
- EIP(32位)/ RIP(64位):指向将要执行的下一条指令的地址。
标志寄存器
- EFLAGS(32位)/ RFLAGS(64位):包含状态标志、控制标志和系统标志。
- 例如:ZF(Zero Flag),CF(Carry Flag),SF(Sign Flag),OF(Overflow Flag)。
控制寄存器
- CR0, CR2, CR3, CR4:用于控制CPU的操作模式(例如,启用保护模式、分页等)。
调试寄存器
- DR0-DR7:用于硬件断点调试。
浮点寄存器
- ST0-ST7:用于浮点运算。
- XMM0-XMM15(SSE指令集):用于SIMD运算。
特殊用途寄存器
- IDTR(中断描述符表寄存器):指向中断描述符表的基地址和界限。
- GDTR(全局描述符表寄存器):指向全局描述符表的基地址和界限。
- LDTR(局部描述符表寄存器):指向局部描述符表的选择子。
ARM架构中的寄存器
ARM架构寄存器包括:
- R0-R12:通用寄存器。
- R13(SP):栈指针。
- R14(LR):链接寄存器,保存子程序返回地址。
- R15(PC):程序计数器。
- CPSR(Current Program Status Register):当前程序状态寄存器。
不同的CPU架构有不同的寄存器集,但大致都分为通用寄存器、特殊用途寄存器和状态寄存器等。
问题
地址空间大小:
- 32位机器的地址总线宽度为32位,因此可以寻址的最大内存空间为2^32字节,即4GB。
- 64位机器的地址总线宽度为64位,可以寻址的最大内存空间为2^64字节,这是一个极大的数值,几乎可以覆盖所有可能的内存需求。
寄存器大小:
- 32位机器中,通用寄存器的宽度通常为32位。
- 64位机器中,通用寄存器的宽度通常为64位,这使得64位机器能够在单个指令中处理更多的数据。
指令集:
- 64位机器通常支持更多的指令集扩展,包括更多的SIMD指令和更高级的指令集,以支持更复杂的计算和操作。
性能:
- 64位机器通常具有更高的性能,因为它们可以处理更多的数据和更大的内存空间,从而更有效地执行计算任务。
内存寻址:
- 64位机器使用更长的内存地址来访问内存,这意味着可以直接访问更大的内存空间,而无需进行分段或分页。
总的来说,64位机器相对于32位机器具有更大的地址空间、更大的寄存器、更丰富的指令集和更高的性能,这使得它们能够处理更复杂和更大规模的计算任务。
内存
/*dword ptr:表示操作数的大小和类型,这里指定了操作数是一个双字(32位)的数据。
ss:表示使用的段寄存器,这里表示堆栈段(Stack Segment),即栈空间。
[ebp-0x3C]:是一个内存地址引用,它表示相对于基址指针(ebp)的偏移量为0x3C的位置。在栈桢中,ebp 通常指向当前函数的栈底,因此 [ebp-0x3C] 实际上是指向当前函数的栈空间中的某个位置,偏移量为0x3C。
综合起来,dword ptr ss:[ebp-0x3C] 表示从当前函数的栈空间中读取一个32位的双字数据。*/
dword ptr ss:[ebp-0x3C]
介绍一下堆栈:它们是用于存储程序运行时的数据和临时变量的区域,但它们具有不同的特性和用途。
- 栈(Stack):栈是一种后进先出(LIFO)的数据结构,用于存储函数调用和局部变量。当一个函数被调用时,它的参数、局部变量和返回地址会被压入栈中,当函数执行完成后,这些数据会被弹出栈。栈的大小在程序启动时就确定了,它的内存空间由编译器或操作系统管理。栈上的数据通常具有较短的生命周期,函数调用结束后就会被自动释放。
- 堆(Heap):堆是一种动态分配的内存区域,用于存储程序运行时动态分配的内存块。堆上的内存块由程序员手动申请和释放,它的大小和生命周期由程序员控制。堆的大小通常比栈大得多,它可以存储任意大小的数据。堆上的数据通常具有较长的生命周期,直到程序显式释放这些内存块或程序结束时才会被释放。
指令
顺着跳转到错误弹窗je指令找到了核心判断逻辑
00401D9A . 66:3BFE cmp di,si
00401D9D . 0F84 A0000000 je Andréna.00401E43
cmp di,si:这条指令是比较 di 寄存器中的值和 si 寄存器中的值。具体来说,它计算 di - si 的结果,并根据结果设置相应的标志位。
如果 di 中的值等于 si 中的值,则零标志位(ZF)将被设置为1,否则被清零。
如果 di 中的值小于 si 中的值,则符号标志位(SF)将被设置为1,否则被清零。
如果 di 中的值与 si 中的值的最高位(符号位)相同,则溢出标志位(OF)将被设置为1,否则被清零。
跳转指令
je(Jump if Equal),当零标志位(ZF)为1时跳转
jne:Jump if Not Equal,如果ZF为0,则跳转。
js:Jump if Sign,如果SF为1,则跳转。
jns:Jump if Not Sign,如果SF为0,则跳转。
jo:Jump if Overflow,如果OF为1,则跳转。
jno:Jump if Not Overflow,如果OF为0,则跳转。
jc:Jump if Carry,如果CF为1,则跳转。
jnc:Jump if Not Carry,如果CF为0,则跳转。
jz:Jump if Zero,与je相同,如果ZF为1,则跳转。
jnz:Jump if Not Zero,与jne相同,如果ZF为0,则跳转。
jl:Jump if Less,如果SF和OF不同,则跳转。
jle:Jump if Less or Equal,如果ZF为1或SF和OF不同,则跳转。
jg:Jump if Greater,如果ZF为0且SF和OF相同,则跳转。
jge:Jump if Greater or Equal,如果SF和OF相同,则跳转。
其他指令
/*这条指令是加载有效地址(Load Effective Address)的指令,用于将 ebp-0x28 的内存地址计算出来并存放到 ecx 寄存器中。在这里,它的作用是将栈上偏移为 0x28 的内存地址加载到 ecx 中。*/
00401D81 . 8D4D D8 lea ecx,dword ptr ss:[ebp-0x28]
/*这条指令是将 edi 寄存器的值取反(negate)。即将 edi 中的值取负数。*/
00401D84 . F7DF neg edi ; Andréna.<ModuleEntryPoint>
/* 这条指令是将 edi 寄存器的值与自己进行借位减法(Subtract with Borrow),并将结果存放到 edi 中。由于 edi 与自身相减,所以实际上是将 edi 寄存器清零。*/
00401D86 . 1BFF sbb edi,edi ; Andréna.<ModuleEntryPoint>
/*这条指令是将 edi 寄存器的值加一(Increment),即将 edi 中的值加上1。*/
00401D88 . 47 inc edi ; Andréna.<ModuleEntryPoint>
/*这条指令是再次将 edi 寄存器的值取反(negate),即将 edi 中的值取负数。*/
00401D89 . F7DF neg edi ; Andréna.<ModuleEntryPoint>
其中我们发现:
由Strcmp关键字我们可以轻松得出,用户输入的key同SynTaX 2oo1比较,后跳转相应逻辑处理,验证得:
其中我们发现:
[外链图片转存中…(img-6iBaVcyA-1716694304177)]
由Strcmp关键字我们可以轻松得出,用户输入的key同SynTaX 2oo1比较,后跳转相应逻辑处理,验证得:
[外链图片转存中…(img-PCWmNbbO-1716694304177)]