下面是网上的160个CrackMe的部分逆向笔记,包括逆向思路、注册机实现和逆向中常用的知识整理

注意:逆向前一定要先操作一下软件,熟悉软件的运行现象;逆向一定要自己操作一遍,看是很难看会的(高手除外)

文章目录

  • 1.现象
  • 2.NAG窗口破解
    • 思路1:Timer思路(特殊场景)
    • 思路2:偏移4C思路(通用法)
      • VB程序启动顺序
      • 破解步骤
        • step 1.找VBHeader结构起始地址
        • step 2.找VBHeader中偏移4C处的内容
        • step 3.更改窗口的启动顺序
  • 3.序列号破解
    • key 1.用户名生成临时序列号
    • key 2.连续3次浮点运算
    • 注册机
  • 4.扩展:浮点类型的汇编
    • 浮点寄存器
    • 常用浮点指令
    • 示例
  • 5.参考

CrackMe002和CrackMe003是同一个作者用VB写的小程序;CrackMe003多了一个NAG窗口,难度也不是很大

1.现象

运行软件,会先弹出一个NAG窗口,什么也不能操作,几秒钟后会弹出验证用户名和序列号的主窗口

要求:需要去掉NAG窗口和逆向出正确的序列号

2.NAG窗口破解

思路1:Timer思路(特殊场景)

前置知识

  • 基地址:PE文件加载到内存后被称为映像文件(Image File),映像文件优先载入的地址是由PE文件中的ImageBase决定(相对地址),默认是0x400000
  • 第一行代码地址:是由PE文件的AddressOfEntryPoint(即脱壳中的EP)决定,默认是0x01000


因此,正常的程序在0x401000(= 0x400000 + 0x01000)开始执行第一行代码

  • 1.猜测

程序的NAG几秒钟后会自动消失,猜测可能是类似定时器的机制控制的

注意:逆向就是要大胆猜测,然后实验猜测是否正确?有时要实验很多种才会成功,其实这与调试程序bug是一样的思路

  • 2.实验

在内存窗口中,先定位到0x401000位置,然后Ctrl+B搜索Timer(Timer是VB程序默认的定时器变量),搜索结果如下:

VB中计时器的单位是ms,上图中0x1B58 = 7000ms = 7s;重新运行程序,看一看是不是大概7s时间,NAG窗口消失,发现果然是,说明猜测是正确的(可以说是运气好,但是只有逆向多了才会有这种好运气的)

  • 3.破解思路

因此,Timer思路就是将0x1B5改成一个很小的值(比如0x001);现象就是NAG一闪而过,很难被捕捉到,给人的感觉就是NAG窗口被去掉了

  • 4.破解操作

    下面是破解的操作步骤

    • 1.OD加载程序,内存窗口中Ctrl+G,定位到0x401000
    • 2.Ctrl+B搜索Timer,修改计数器变量对应秒数为0x0001(要注意好大小端)

局限性:计时器默认名如果不是Timer,内存中搜索的方法就会失效

思路2:偏移4C思路(通用法)

VB程序启动顺序

VB程序的每个窗口都有启动顺序,这个顺序就保存在程序开始执行位置的偏移4C附近定义的一个结构体中

  • 当前顺序:现在程序中会先启动NAG窗口,后启动序列号验证窗口

  • 破解思路:如果找到启动顺序位置,将NAG窗口放在序列号验证窗口后面,自然就自动去除掉NAG窗口了(想法是好的,就是不知道怎么实现?继续看下面吧…)

下面是VB程序可能的框架:

VB涉及到的相关结构体:

//VBHeader结构定义
Signature               array[1..4] of char;        //00H,签名,必须为VB5!
LanguageDll             array[1..14] of char;       //06H,语言链接库名,通常为”*"或者vb6chsdll
...
AGUTTable               DWORD;                      //4CH,指针,指向Form GuI描述表,***关键位置***
...//AGUTTable结构定义(大小是0x50)
Signature                DWORD                    //00H,必须是50000000
FomID                    TGUID                    //04H,可能是以GUID方式命名的formID
Index                    BYTE                     //24H,窗体的序号,***关键位置***
Flag1                    BYTE                     //28H,第一个窗体的启动标志,可能是90 也可能是10
AGUIDescriptionTable     DWORD                    //48H,指针指向以“FFCC…“开始的FormGUI表
Flag3                    DWORD                    //4CH,意义不明

AGUTTable结构体中,偏移是0x24的Index就是启动顺序;索引到AGUTTable位置是通过VBHeader为基准,偏移0x4C;因此使用修改启动顺序的方法也叫4C思路

破解步骤

step 1.找VBHeader结构起始地址

OD加载程序,没有加壳的程序默认会停在OEP处,VB程序典型的OEP附近汇编如下,多调试几次VB程序自己就会发现

00401164   .- FF25 4CB14000   jmp     dword ptr ds:[40B14C]  ; MSVBVM50.EVENT_SINK_Release
0040116A   $- FF25 8CB14000   jmp     dword ptr ds:[40B18C]  ; MSVBVM50.ThunRTMain
00401170 > $  68 D4674000     push    4067D4              ; 00401170是OEP指向地址,OD加载后会停在这行
00401175   .  E8 F0FFFFFF     call    0040116A               ; <jmp.&MSVBVM50.#100>
#说明:入口点处的push压入stack的数据就是VBHeader首地址,即VBHeader首地址是4067D4

step 2.找VBHeader中偏移4C处的内容

内存窗口中,Ctrl+G,定位到4067D4地址,偏移4C处(AGUTTable结构)的内容是0x406868

step 3.更改窗口的启动顺序

内存窗口中,定位到0x406868,会发现2块类似的结构(AGUTTable结构),每块的大小是0x50个bytes,查看每块结构的偏移0x24

  • NAG窗口:启动顺序是00,即第一个被程序加载的窗口

  • 序列号验证窗口:启动顺序是01

去掉NAG窗口方法:直接将NAG窗口和序列号验证窗口的启动顺序互换,保存二进制修改

经验证,的确不再显示NAG窗口了;至此,NAG被去掉了,使用了2种方式,推荐使用第2种

3.序列号破解

这个程序与CrackMe002的逆向思路是一样的,暴力破解和直接通过函数栈帧找到正确序列号的逻辑在CrackMe002里有介绍,下面是总结的操作流程:

  • 1.先输入错误的用户名和序列号(test123/456),根据错误弹窗里的字符串先找到调用弹窗的代码和关键跳转

  • 2.在关键跳转所在函数起始位置设置断点,反复调试函数起始位置和关键跳转之间的代码,分析根据用户名生成序列号的逻辑

笨方法,继续用上面的思路破解CrackMe003的序列号;为了写出注册机,下面将调试时发关键节点整理成了笔记(一定要自己操作一下,你才会知道下面说的是什么意思)

key 1.用户名生成临时序列号

调试中发现了如下计算临时序列号的公式:

临时序列号 = 用户名长度 * 0x15B38 + 用户名第一个字符的ASCII码,结果用十进制表示的字符串

示例:用户名test123对应的临时序列号(字符串)是622332(记住这个值,后面会用到)

key 2.连续3次浮点运算

用户名计算出临时序列号会经历3次浮点运算操作,操作套路基本一样(如果不熟悉浮点运算,通过单步调试观察栈帧,一样可以得到下面的结果);下面直接给出了3次操作的截图

  • 第一次操作622332 -> 622334

  • 第二次操作622334*3-2=1867000

  • 第三次操作1867000+15 -> 1867015

注册机

经过上面key1和key2,很容易写出简单的注册机

#include "StdAfx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {char user_name[100] = {0};                 //用户名printf("请输入用户名:");scanf_s("%s", user_name, 100);//计算序列号int user_serial = strlen(user_name) * 0x15B38 + user_name[0];//用户名计算临时序列号float serial = 0.0;serial = user_serial + 2.0;                    //第一次操作serial = serial * 3.0 -2.0;                 //第二次操作serial = serial + 15.0;                        //第三次操作printf("用户名:%s, 对应的序列号:%f\n", user_name, serial);system("pause");return 0;
}

验证结果如下,说明整个逆向的思路和注册机是正确的

如果你是第一次逆向浮点运算,可以看一下我以前整理的浮点汇编的笔记(直接粘贴在下面了);如果想学一下C++代码逆向成汇编的典型特征,推荐看《C++反汇编与逆向分析》;如果是大牛,可以直接忽略下面

4.扩展:浮点类型的汇编

CrackMe003的生成序列号算法使用了浮点的相关运算,下面简要介绍逆向中浮点类型的相关知识

C++中,32位操作系统中2种浮点数据类型:

  • 单精度(float):内存中占用4个bytes
  • 双精度(double):8个bytes

浮点类型的编码就不详细介绍了,对于逆向来说,只要知道基本格式(符号位 + 指数部分 + 科学计数法中的位数部分)就行,下面主要介绍一下浮点数指令

浮点寄存器

  • 区别:普通数据类型操作使用的是通用寄存器(eaxecx等),浮点数据类型操作使用的是浮点寄存器(ST0 ~ ST7

  • stack实现:浮点寄存器是通过使用栈(stack)来实现的,共8个栈空间组成(ST0 ~ ST7),且每个浮点寄存器占用8个bytes,浮点寄存器使用类似于入栈和出栈的操作

  • 使用顺序:每次操作的都是ST0,从而影响其他浮点寄存器(ST1 ~ ST7

    • 入栈:如果ST0中没有数据,直接放进ST0;如果ST0中有数据,ST7数据丢弃,依次将ST6数据放入ST7,…,ST0数据放入ST1,新数据放入ST0
    • 出栈:执行相反操作

常用浮点指令

指令 使用方法 说明
fld/fild fld/fild PUSH_DATA 将浮点数/整数PUSH_DATA压入ST0中
fst/fist fst/fist POP_ADDR 将ST0中的数据以浮点/整数形式存入POP_ADDR地址中
fstp/fistp fstp/fistpPOP_ADDR 相对于fst/fist,会多执行一次出栈操作
fldz、fld1 fldz、fld1 将0.0、1.0压入ST0中
fadd fadd addr 将addr地址内的数据与ST0做加法,结果存入ST0中
fcom fcom addr 将addr地址内的数据与ST0进行实数比较,影响对应标志位
ftst ftst 比较ST0是否是0.0,影响对应标志位

说明:以p结尾的指令基本都会执行一次出栈操作;其他运算指令与普通指令类似,只需要在指令前面加一个f即可

示例

Debug版本的浮点操作示例(C++代码与反汇编代码对应)

#include "stdafx.h"
#include <windows.h>
int main(int argc, char* argv[])
{;---生成栈帧和stack上分配部分空间的初始化代码--- int test_int = 3;
0096B65E  mov         dword ptr [test_int],3    float test_float = (float)test_int;            //通过ST0做中转,将int转成float类型
0096B665  fild        dword ptr [test_int]                      ;将整数test_int压入ST0中
0096B668  fstp        dword ptr [test_float]                    ;将ST0中的数据以浮点的形式存入test_float,且ST0中数据出栈printf("test_float=%f", test_float);        //float数据通过ST0中转后,放入stack上预留好空间
0096B66B  fld         dword ptr [test_float]                    ;将浮点数test_float压入ST0中
0096B66E  sub         esp,8                                     ;浮点数作为变参函数的参数,需要转换成双精度浮点存储在stack上
0096B671  fstp        qword ptr [esp]                           ;将ST0中的数据以浮点的形式存入eap执行的地址,且ST0中数据出栈
0096B674  push        offset string "test_float=%f" (9BDC7Ch)
0096B679  call        @ILT+4360(_printf) (96A10Dh)
0096B67E  add         esp,0Ch  test_int = (int)test_float;
0096B681  fld         dword ptr [test_float]                    ;将浮点数test_float压入ST0中
0096B684  call        @ILT+2085(__ftol2_sse) (96982Ah)        ;调用_ftol函数进行浮点数转换
0096B689  mov         dword ptr [test_int],eax  return 0;
0096B69D  xor         eax,eax
}

简要结论:

  • 1.通过ST0寄存器实现整数和浮点数的转换

  • 2.float类型的浮点数占用4个bytes空间,但是在实际处理时都是按照8个bytes方式进行处理

  • 3.浮点数作为参数,不能直接压入stack中;因为push指令只能传4个bytes大小,会出现数据损失(printf以整数方式输出浮点数会出现错误的根因);作为返回值也有类似的处理

至此,CrackMe003逆向完了,想学逆向就尽量不要爆破掉程序就完事,尽量多学点里面的基础知识

5.参考

  • 1.VB程序逆向反汇编常见的函数 - 笨笨D幸福 - 博客园 (cnblogs.com)
  • 2.常用软件可以在这里下载:爱盘 - 最新的在线破解工具包 (52pojie.cn)
  • 3.160个Crackme_鬼手56的博客-CSDN博客
  • 4.《使用OllyDbg从零开始Cracking》系列的文章也不错

CrackMe003:NAG窗口(4C法)和浮点计算相关推荐

  1. 去VB程序NAG窗口方法-4C法

    去除VB程序的程序启动时的NAG窗口,基本原理就是寻找到每珍具窗口的启动顺序,再改变窗口的启顺序就可以了. 具体实列如下: 当程序启动时,会出现一个NAG窗口,如下所示: OD载入程序:EP处 VB程 ...

  2. nag在逆向中是什么意思_OD 实验(四) - 去除 NAG 窗口的几种方法

    程序: 运行 弹出一个窗口,说要注册 点击确定,到主窗口 关闭主窗口 然后弹出提醒注册的对话框 逆向程序 用 OD 打开程序 GetModuleHandleA 获取程序模块的句柄,程序在内存中的基址 ...

  3. OllyDbg笔记-初识PE文件(nag窗口破解)

    目录 基本概念 代码与实例 基本概念 这里主要是记录下PE文件结构: PE文件结构,它在硬盘上的存储结构跟载入内存时候的存储结构是一样的.  在PE文件结构里边找出想要的东西,当这个文件映射到内存后, ...

  4. 4. OD-去除烦人的nag窗口(去除提醒用户购买正版的警告窗口)

    所有函数返回值均放入eax中 扩展修改nop 选中语句->右键菜单->二进制->用nop填充 三种方式 1. 修改标志位je为jmp 2. 扩选判断语句+call,全部改为nop 3 ...

  5. 去除WinRAR 5.01(32位) NAG窗口

    前阵子重装系统,顺手下了一个免费的WinRAR(32位 版本号5.01).用了没多久发现这货带NAG窗口,关闭NAG窗口后居然还跳出广告窗口,如下图,不胜其扰下决定去除NAG窗口. 毕竟WinRAR是 ...

  6. 逆向破解--除去软件nag窗口

    作者是名新手,能力有限,文章中如果有和不正确的地方,希望各位前辈指出 本文仅作为学习的记录,做分享- 我们有时候会用非注册软件,然后软件提供者希望更多的人注册他的软件,因此烦人的nag窗口出现了,不堪 ...

  7. nag在逆向中是什么意思_OD调试4----去除nag窗口的几种方法

    本实验所用程序如下,一个主窗口,两个nag窗口.nag本意为烦人唠叨的意思.在这里指的是不断弹出来窗口,例如注册窗口. 这里第一个和第三个为烦人的nag窗口,这里我们要将它去除.接下来就介绍四种方法, ...

  8. LeetCode 674. 最长连续递增序列 (滑动窗口 计数法)

    LeetCode 674. 最长连续递增序列 滑动窗口 右边界不断往右移动 左边界收缩条件:当右边界的值小于等于其左边的值时(递减) 左边界收缩到右边界当前位置 class Solution {pub ...

  9. linux终端窗口玩法

    ctrl + shift + = 放大终端窗口的字体显示 ctrl + - 缩小终端窗口的字体显示 开启多个窗口(不在一个窗口) Ctrl + Alt + T Alt + n对应的就会切换到第n个终端 ...

最新文章

  1. 开发日记-20190807 关键词 读书笔记《Linux 系统管理技术手册(第二版)》DAY 21
  2. spring-mybatis.xml 访问html5,Spring mvc无xml配置及利用JdbcTemplate访问数据库
  3. leetcode#42 Trapping rain water的五种解法详解
  4. Java zip 压缩 文件夹删除,移动,重命名,复制
  5. Be My Eyes app:我是你的眼
  6. 黑客专用Linux发行版Kali Linux发布滚动更新版2016.1
  7. 性能测试:性能测试指标评估方法
  8. 查看mysql所有命令
  9. sqoop增量导入hive_Sqoop 增量导MySQL数据 至Hive
  10. Android IPC(二)Messenger实现跨进程双向通信
  11. javamail 邮件发送、带格式、已保存
  12. 教你如何学习思维导图
  13. 期货交易有什么套利技巧?
  14. 像素(px)到底是个什么单位
  15. 软件架构的10个质量属性
  16. git删除所有文件夹(清空远程仓库)
  17. ganache命令行安装
  18. Android秀翻天的操作——使用协程进行网络请求
  19. 当在浏览器中输入一个域名后,会发生什么
  20. Android 性能优化之线程优化

热门文章

  1. 阿里研究院启动2017年度淘宝村辅助认证活动(附表格下载)
  2. win10WLAN选项消失解决方法
  3. 每日一学 | 2021-05-19 | Power BI 学习笔记03、04
  4. [笔记]unity渲染类零碎代码记录(100多条)
  5. 光伏发电站|太阳能电池板辐照度(4G)无线直流电压汇集电流测量采集监控技术方案
  6. [ web 漏洞篇 ] 常见web漏洞总结之 RCE 远程代码 / 命令执行漏洞总结
  7. 软件产品发布基本流程
  8. 打开日志管理的潘多拉盒子
  9. 5G 和 WiFi-6,谁是智能制造的主角?
  10. 间充质干细胞最新研究成果进展(2021年10月)