吾爱汇编

 找回密码
 立即注册

QQ登录

绑定QQ避免忘记帐号

查看: 6321|回复: 108

[原创逆向图文] 对一个文字转语音软件的分析

  [复制链接]
白云点缀的蓝 发表于 2021-7-28 23:02 | 显示全部楼层 |阅读模式

本帖最后由 白云点缀的蓝 于 2021-11-9 22:25 编辑

我们od,然后在od里找找相关关键信息
od载入后,我们右键中文搜索引擎,选择智能搜索
7.jpg

我们根据前面的开通会员的弹窗信息来进行搜索过滤

8.jpg

扩展:od里搜索出来的东西是什么呢?
我们打开visual studio工具来做个分析
我们点击文件,然后选择新建,然后选择项目
9.jpg

选择c++,然后选择windows,然后选择空项目,最后点击下一步

10.jpg

11.jpg

设置项目的存放路径,还有项目名称,设置好后,我们点击创建



12.jpg

然后我们右键源文件,选择添加新建项

13.jpg

点击新建项后,我们选择c++文件,把名称的后缀改为c,然后点击添加
14.jpg

我们在文件中写如下代码,

[C] 纯文本查看 复制代码
#include<Windows.h> 
int main() {

        MessageBoxA(NULL, "这个字符串在od中能看到吗", "吾爱汇编",NULL);
return 0;
}

这个MessageBoxA的功能是弹出一个对话框


20.jpg

#include<Windows.h>  //Windows.h类似于一个菜单,你去餐馆点菜的时候,通常都会给你一个菜单然后你就从中选择一个想要的菜,这个MessageBoxA就相当于一个你想要的菜。,也就是说MessageBoxA,他在Windows.h这个文件中。
#include就相当于导入一个菜单,固定写法,后面的<>,两个大于小于代表你要包含一个系统的头文件,Windows.h就是一个系统的头文件。
int main(){}这个又是什么呢?这个是一个main函数,一个程序的入口点,没有入口点,你的程序里的代码就无法运行,int这个代表是一个整型的返回值,这个int占4个字节。一个字节由八个bit组成,这个比特是由0和1组成的,在计算机的世界中,计算机只能识别0和1,八个bit,一个bit有两种选择,分别为0,和1,比如   一个字节   0000 0000 这个就是八个bit,四个字节也就是32个比特,0000 0000 0000 0000 0000 0000 0000 0000
最高位是一个符合位,0为正整数,1为负数。
int的表示范围是:-2^31 (-2147483648) ~ 2^31-1 (2147483647),这个int就是一个数字而已,没有小数点,一个基本数据类型
下面是其他一些数据类型

15.jpg

unsigned就是无符合的意思,也就是说最高位即使为1他也为正数,我们拿unsigned int举例
1111 1111 1111 1111 1111 1111 1111 1111,以下是计算器计算出来的值

在计算前我们需要把计算器选择为程序员模式

17.jpg

16.jpg

下面是一些浮点类型的数据类型,他们都有小数点,相比前面的整型数据类型

18.jpg

return 0;//这个是什么意思呢?return是返回的意思,因为int main这个入口函数前面有个int,所以他的返回值就是int类型的,也就是这个,-2^31 (-2147483648) ~ 2^31-1 (2147483647),我们可以把后面的0随意替换成int类型范围内的数字即可,
我们分析一下这个函数,MessageBoxA(NULL, "这个字符串在od中能看到吗", "吾爱汇编",NULL);
我们按住ctrl+鼠标右键转到定义,点击MessageBoxA

19.jpg

int
WINAPI
MessageBoxA(
    _In_opt_ HWND hWnd,
    _In_opt_ LPCSTR lpText,
    _In_opt_ LPCSTR lpCaption,
_In_ UINT uType);

我们可以知道,这个函数的返回值是int类型的,我们分析一下这个WINAPI
我们同样Ctrl+鼠标左键转到定义
21.jpg

我们可以看到如下代码,

#define WINAPI      __stdcall
这句代码的意思是
#define 固定写法,他的意思是定义一个全局常量,什么是常量呢?就是不能在程序运行时改变的一个值  WINAPI这个就是常量的名称,
__stdcall这个就是这个常量的值
这个__stdcall
是一个关键字,就是你不能拿他起名字,全局代码中你都不能拿这个来定义变量。且你写上他后就有特殊的功能
什么是变量呢?
int a = 10;这个就是定义一个变量,
int这个是变量的数据类型,a就是这个变量的名字,=10就是给a这个地址里面赋值。
变量名相当于一个地址,然后地址里面存了10这个值,地址是什么呢?地址就是一个16进制的数,相当于一个编号,对一个数据存放的地方取一个编号,比如0x6666666,这个就是一个地址,地址里面可以放数据,也可以再放一个地址,然后放的地址里面又有数据,我们从中延申出指针,指针就是地址,一级指针就是在地址中单纯放一个数据,二级指针就是地址里面放地址,然后最里面那个地址放数据,
int a = 10; //定义一个变量
        int* p = &a;//取存放变量a的地址
        printf("p= %x\n", p); //打印变量
        printf("*p=%d\n", *p);//打印指针里面存放的数据
我们对上面的代码进行分析,
int* p = &a;//这个就是定义一个指针变量,什么是指针变量?就是存放指针的变量,也就是说存放地址的变量,一级指针定义格式 ,这个int就是你这个地址里面要存放什么样的数据类型,int的话,那就是存放-2^31 (-2147483648) ~ 2^31-1 (2147483647) 这个范围的数据,其他的数据类型比如double,char ,float等都可以,但是地址是固定的,也就是说地址在0x00000000-0xFFFFFFFF这个范围内,正好是4个字节,这里我们说的是32位的地址,无论你定义什么样的指针,地址都是4个字节的,但是地址里面存放的数据可能不一样,因此我们延伸出数据类型,这个数据类型我在前面有将,大家可以翻到前面去看看,这个&a中的&是取地址的意思,对变量a进行取地址,然后赋值给指针p,
printf("p= %x\n", p);,这个就是打印一个变量,在使用前,我们需要导入一个系统的头文件,相当于一个菜单,有了菜单,我们才可以点菜,这个头文件是stdio.h,因为是系统的头文件,所以我们要加<>,如果是自己定义的头文件,我们就改成双引号就行“”,也就是这样#include <stdio.h>
printf("p= %x\n", p),这个函数中第一个参数是格式,第二个参数是你要打印的变量,%x是打印一个16进制数,因为这个p是地址,所以我们要用%x,这个\n就是换行的意思,这个p=可以随便写,好识别就行,%d就是打印一个整型数据。*p就是取p地址里面的值,因为p的地址是从a那里获取的,所以*p就是10;

22.jpg

当我们看见类似xxxxxx();那这个就是函数了,函数名xxxxxx,()这个括号里面放参数即可,
下面我们演示一个二级指针
int** pp = &p;
        printf("pp= %x\n", pp);
        printf("*pp= %x\n", *pp);
        printf("**pp= %x\n", **pp);
**代表这是一个二级指针,有多少个*就代表是几级指针
&p代表对指针p取地址,也就是存放指针p的地址,printf("pp= %x\n", pp);
这个就是打印pp的地址,*pp就是取pp里面值,因为二级指针pp是一级指针p的地址,所以在pp前面加个*就是取的指针p的地址,指针p的地址又是变量a的地址,所以**p就是取a地址里面的值,也就是10;


23.jpg

我们回到__stdcall这个关键字上面,被__stdcall关键字修饰的函数,他的参数是右向左通过堆栈传递的
我们把我们的写好的程序放入od看一下,我们先生成一下exe文件,
我们右键中文搜索引擎,然后选择智能搜索

25.jpg

我们双击吾爱汇编,然后在如下位置下断点。
扩展一下基础知识,push就是往堆栈里面放数据
下面这块红色的位置就是堆栈
00121773    6A 00           PUSH 0x0
00121775    68 307B1200     PUSH 0x127B30                            ; 吾爱汇编
0012177A    68 387B1200     PUSH 0x127B38                            ; 这个字符串在od中能看到吗
0012177F    6A 00           PUSH 0x0
PUSH 0X0就是把NULL放入堆栈,这个0x0也是一个地址,只不过他是空地址,
PUSH 0x127B30 这个就是把 0x127B30这个地址放入堆栈,这个地址里面存放了吾爱汇编这个字符串,也就是说存放吾爱汇编这个字符串的地址是一个一级指针,
PUSH 0x127B38 这个就是把 0x127B38 这个地址放入堆栈,这个地址里面存放了这个字符串在od中能看到吗这个字符串,这个地址是一个一级指针
PUSH 0x0 这个就是把NULL放入堆栈,这个0x0也是一个地址,只不过他是空地址,
c语言中NULL就是空的意思,也就是空指针,他是一串0x00000000的地址,简写位0x0

27.jpg

我们下断点后,点击运行执行到下面这段代码,这个call就对应着代码里的MessageBoxA函数,
这个在代码段下断点原理是什么呢?
断点的原理是在断点处重写代码,插入一个int3中断指令,当CPU执行到int3指令的时候,OD就可以获得控制权。也就是说,当你下断点的时候,od会把你下断点的位置改为int 3指令,这个int 3指令与push类似,也是一条汇编指令,我们常常把这个int 3断点称为CC断点,原因是,int 3的汇编代码在od中的十六进制就是CC,

29.jpg

为什么我们看不见在断点出的int 3呢?因为这个od处理过了,因此我们看不到这个int 3汇编代码
这个int 3,也就是CC 断点,常常用来检测软件是否被od调试了,
00121781    FF15 98B01200   CALL DWORD PTR DS:[0x12B098]             ; user32.MessageBoxA
我们拿一段简单的反调试代码来分析

[C++] 纯文本查看 复制代码
#include <iostream>
#include <windows.h>
using namespace std;
int main() {
        FARPROC Uaddr;
        BYTE Mark = 0;
        Uaddr = GetProcAddress(LoadLibrary(L"user32.dll"), "MessageBoxA");
        Mark = *((BYTE*)Uaddr);//取Messagebox函数的第一字节

        if (Mark == 0xCC)
        {
                MessageBoxA(NULL, "bad guy ", "", MB_OK);
                return TRUE;//发现断点
        }
        MessageBoxA(NULL, "good boy", "", MB_OK);
        
        cout << "hello" << endl;
        system("pause");
        return 0;
}

#include <iostream>  
包含一个头文件iostream,c++中有些头文件后面的后缀.h默认省略
因为这是一个系统头文件,所以需要加<>
#include <windows.h> 包含一个windows的系统头文件

using namespace std;这个是使用一个命名空间,using namespace这个是固定的写法,
std可以变换,这个std也可以类比成一个菜单,std里面也有很多函数,我们使用这个std命名空间后,里面的函数,我们在全局范围内都可以使用,比如cout << "hello" << endl;
这个就是在c++中的打印hello,这个cout需要在使用std这个命名空间后才可以使用,endl是换行的意思,相当于\n
我们看看这个FARPROC Uaddr;这个是定义一个函数指针变量,名字叫Uaddr
我们Ctrl+左键,转到定义
typedef int (FAR WINAPI *FARPROC)();
这个就是定义一个函数指针,用来存放函数的地址的,typedef就是定义
返回值为int类型,FAR代表他是远程地址调用,因为MessageBox这个函数地址相比自己的写的程序是很远的,WINAPI这个我前面说了,这个是__stdcall 代表函数他的参数是右向左通过堆栈传递的*代表这是一个指针,FARPROC代码这是一个函数指针的名字
我们再看一下这个变量,BYTE Mark = 0;变量类型为BYTE ,变量名为Mark;
我们同样转到定义,可以看到他是一个无符号整型的一个数据类型。
这个typedef相当于给 unsigned char 取了一个别名,叫BYTE
typedef unsigned char       BYTE;
我们分析一下GetProcAddress,我们转到定义,
可以看到他的返回值是FARPROC也就是说我们要用 int (FAR WINAPI *FARPROC)();这个来接收他,所以我们要定义一个变量来接收他FARPROC Uaddr就是这个,WINAPI就不用多说了吧前面讲了两遍了__stdcall,这个是一个调用规范,规范一个参数的传递方式,也就是在堆栈中的存入顺序
GetProcAddress这个是函数名
hModule这个是函数的第一个参数
lpProcName这个是函数的第二个参数
FARPROC
WINAPI
GetProcAddress(
    _In_ HMODULE hModule,
    _In_ LPCSTR lpProcName
);
我们转到定义,分析一下下面这两个参数是什么
LPCSTR :CHAR *LPCSTR, *PCSTR  这个我们可以知道,他是一个指针,存放的数据类型为CHAR类型的
HMODULE :这个是一个句柄,只有拿到句柄后,我们才可能有权限操作,

我们看一下第一个参数,这个是加载库文件,因为MessageBoxA函数就在这个user32.dll里面,所以我们要调用这个函数,这个函数他会返回一个句柄,也就是HMODULE ,我们可以把这个LoadLibrary(L"user32.dll")就理解成HMODULE ,因为他的返回值就是HMODULE ,

下面这个是LoadLibrary函数的定义,为什么是LoadLibraryW呢?因为下面这句代码,
他把LoadLibraryW改名为LoadLibrary  ,因此LoadLibrary  的原型为LoadLibraryW
#define LoadLibrary  LoadLibraryW

HMODULE   这个是返回值,是一个句柄
WINAPI  这个是调用规范,也就是参数在堆栈中的传递顺序
LoadLibraryW 这个是函数名
LPCWSTR lpLibFileName 这个是函数的参数,也就是库的文件名
LPCWSTR WCHAR *LPCWSTR, *PCWSTR; 可以知道他是一个指针,
我们看看WCHAR 是什么, 这个是定义,
typedef wchar_t WCHAR; wchar_t定义为WHAR,也就是改名
typedef unsigned short wchar_t;把unsigned short改名为wchar_t
也就是说unsigned short是LPCWSTR 的实际数据类型
HMODULE   
WINAPI
LoadLibraryW(
    _In_ LPCWSTR lpLibFileName
    );

LoadLibrary(L"user32.dll")
为什么前面要加个L呢?
这个L告诉我们的c编译器user32.dll字符串按宽字符保存-即每个字符占用2个字节
GetProcAddress(LoadLibrary(L"user32.dll"), "MessageBoxA");
我们看看最后的参数,"MessageBoxA",就是从user32.dll里找MessageA这个函数,实际上,代码变成可执行文件后,每个函数都会有一个地址,不仅仅是变量数据,
获得返回值后,给前面定义好的函数指针变量
下面我们分析下面这个,将Uaddr转为BYTE *类型,在前面我们已经说了,这个BYTE的实际类型是char类,也就是一个字节,也就是说,把Uaddr转为存放一个字节数据的地址,因为我们的CC断点,也就是int 3汇编代码他的十六进制只要一个字节就可以存下,所以char就够了

30.jpg

转为BYTE *类型后,对这个BYTE *类型的地址加个*取里面的值,也就可以取出是否被下断点了
Mark = *((BYTE*)Uaddr);
我们看看下面这个代码,下面这个是条件判断语句
格式为if(条件){
条件成立执行的代码;

}
c语言中非0即真,也就是说除了0之外都是真的,不管你是负数也好,随意一个数都好,只要不是0就是真的。
Mark == 0xCC这个就是进行比较,Mark是前面我们定义的一个变量
判断Mark是否等于0xCC 这个0xCC就是int 3的十六进制代码,如果等于说明被下断点了,
如果下了断点就会弹窗提示为bad guy,我们回到MessageBoxA函数,看看官方说明
hWnd

类型:HWND

要创建的消息框的所有者窗口的句柄。如果此参数为NULL,则消息框没有所有者窗口。

lpText

类型:LPCTSTR

要显示的消息。如果字符串由多行组成,您可以在每行之间使用回车符和/或换行符分隔各行。

lpCaption

类型:LPCTSTR

对话框标题。如果此参数为NULL,则默认标题为Error。

uType

类型:UINT

对话框的内容和行为。此参数可以是来自以下标志组的标志的组合。
第一个参数一般为NULL,我们并不需要用到句柄,不需要进行操控,
第二个参数和第三参数都为CHAR *LPCSTR, *PCSTR;也就是字符指针类型,存放字符的指针,
第二个参数为要提示的消息,第三个为标题,第四个为要显示什么类型的对话框
具体什么类型,可以上官网查看,复制拿来用就行,https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxa
当然我们也分析一下第四个参数是什么
这个是MB_OK的定义
#define MB_OK                       0x00000000L

第四个参数是下面这个
typedef unsigned int        UINT;
他是一个无符号整型

c++中引入的TRUE和False,也就是真和假,实际上就是整型数字取了别名而已
如果发现了的话,就直接返回了,也就是说弹出提示框,bad guy后就退出了,因为一个函数遇到return时,他就代表着这个函数要结束了。
当我们未发现下断点时则会执行这条代码
system("pause");这个是暂停控制台,防止程序一运行窗口就没了。
这个system函数的定义如下
返回值为int ,调用惯例为 __cdecl,函数名为system,
__cdecl惯例的所有参数从右到左依次入栈,这些参数由调用者清除
参数为char指针类型,且这个值无法被修改,因为加了const,
* command就是取值,加了const就是这个值不能被修改
int __cdecl system(
        _In_opt_z_ char const* _Command
        );
return 0;程序正常返回,返回值为0,这个return是固定的,后面的值随便
MessageBoxA(NULL, "good boy", "", MB_OK);
BYTE Mark = 0;
if (Mark == 0xCC)
        {
                MessageBoxA(NULL, "bad guy ", "", MB_OK);
                return TRUE;//发现断点
        }
我们放入od,测试一下我们的反调试,我们需要在MessageBoxA上下断

31.jpg

点运行后可以发现,检测到了
32.jpg

我们聊聊反反调试吧,因为他检测的段首,也就是检测了一个字节,也就是说我们可以往下进行下断了,但是如果他检测整个代码怎么办呢?我们可以尝试在GetProcAddress函数执行的时候进行拦截,让他获取不了MessageBoxA函数的修改数据,从而达到过反调试。
我们回到前面的话题,调用惯例,。


26.jpg

堆栈是一个先进后出的存储顺序
push的在最底下,最后push的在最上面
push的是Style = MB_OK|MB_APPLMODAL是这个,这个是第四个参数
第二个push的参数Title = "吾爱汇编"是这个
第三个push的参数Text = "这个字符串在od中能看到吗"是这个
第四个push的参数hOwner = NULL,
003CF888   00000000  |hOwner = NULL
003CF88C   00917E48  |Text = "这个字符串在od中能看到吗"
003CF890   00917BF4  |Title = "吾爱汇编"
003CF894   00000000  \Style = MB_OK|MB_APPLMODAL
003CF898   00911023  OFFSET Project1.<ModuleEntryPoint>
003CF89C   00911023  OFFSET Project1.<ModuleEntryPoint>

由此证明了,__stdcall 代表函数他的参数是右向左通过堆栈传递的因为我们的参数与传入堆栈的顺序完全相反,倒着传递的

28.jpg
我们回到之前的问题,od中搜索出来的东西在代码中是怎样的呢?
通过下面的图片,我们可以知道,字符串是会显示在od的搜索工具中
那如果是数字,还会显示吗?我们试一试

33.jpg

[C] 纯文本查看 复制代码
#include<Windows.h> 
#include <stdio.h>
int main() {



        int a = 666666;
        int b = 8888888;
        int c = 2222222;
        MessageBoxA(NULL, "这个字符串在od中能看到吗", "吾爱汇编",NULL);
        //int a = 10;
        //int* p = &a;
        //printf("p= %x\n", p);
        //printf("*p=%d\n", *p);
        //int** pp = &p;
        //printf("pp= %x\n", pp);
        //printf("*pp= %x\n", *pp);
        //printf("**pp= %d\n", **pp);
        return 0;
}
我们定义了三个整数,我们点击生成,然后载入od
34.jpg

可以看到,数字并不会显示在od的搜索字符串中

好的,我们回到那个文字语音的转换软件中,定位到那个提示vip会员的位置

35.jpg

可以看到push了字符串的地址,然后调用了函数
我们到上面去看看,看看有没有跳过这个提示的汇编代码

可以看到有个JNZ大跳,跳过了提示开通会员的代码

36.jpg

我们分析一下下面这段代码
0011114E    FFD0            CALL EAX
00111150    0FB6C8          MOVZX ECX,AL
00111153    85C9            TEST ECX,ECX
00111155    0F85 F3020000   JNZ 0011144E                             ; SDTextVo.0011144E
CALL EAX,这个是调用一个函数 eax在代码中,可以理解成一个变量
我们分析一下eax ,eax有8位0x00000000-0xFFFFFFFF
ax就是四位0x0000-0xffff
al就是两位0x00-0xFF
也就是说当我们给ax,赋值为8位的是不行的,
但是ax给8位寄存器的赋值是可以的
小的可以给大的赋值,大的不能给小的赋值
下面这个一大块就是寄存器,
37.jpg

当我们用eax,给al赋值时会提示错误
38.jpg

当我们用eax,给ax赋值时也会提示错误

39.jpg

下面的这些都是32位的寄存器
EAX、ECX、EDX、EBX为数据寄存器;

ESP、EBP为指针寄存器;

ESI、EDI变址寄存器。

E去除后,比如ax,
就变成16位寄存器了,
ax又可以分为al,于ah,
举例子
当我们执行mov ah,66,时可以看到eax的值为11116633
因此6633中的66就是ah

40.jpg

al也一样,我们看图
当我们执行下面的汇编代码的时候
00111168    B0 88           MOV AL,0x88
Eax变为了,11116688

41.jpg

也就是说al就是6688中的88
我们分析一下下面这个汇编代码
0011116A    0FB6C0          MOVZX EAX,AL

执行前eax 为11116688

42.jpg

执行后变为了00000088
也就是说他把111166全部变为了0,只有al变为88

43.jpg

下面我们分析一下test指令
Test指令用于判断一个寄存器值是否为0,如果不为零就把Z标志位变为0,
从而影响JNZ的跳转,JNZ汇编代码只要Z标志为0就会跳转,为1就继续向下执行代码
看图eax并不为零,执行test eax,eax后,JNZ变为0,然后JNZ就跳转了,

44.jpg


我们回到前面的代码

0011114E    FFD0            CALL EAX
00111150    0FB6C8          MOVZX ECX,AL
00111153    85C9            TEST ECX,ECX
00111155    0F85 F3020000   JNZ 0011144E                             ; SDTextVo.0011144E

来个扩展,函数的返回值是存放在eax寄存器的,我们写个代码验证一下

[C] 纯文本查看 复制代码
#include<Windows.h> 
#include <stdio.h>
int test() {

        return 6666;

}
int main() {



        int a = 666666;
        int b = 8888888;
        int c = 2222222;
        MessageBoxA(NULL, "这个字符串在od中能看到吗", "吾爱汇编",NULL);
        test();
        //int a = 10;
        //int* p = &a;
        //printf("p= %x\n", p);
        //printf("*p=%d\n", *p);
        //int** pp = &p;
        //printf("pp= %x\n", pp);
        //printf("*pp= %x\n", *pp);
        //printf("**pp= %d\n", **pp);
        return 0;
}

我们自己写一个函数,函数名为test,返回值为int类型,我们返回6666这个值;
int test() {

        return 6666;

}
记得要调用,如果没调用的话,写了也没用
我们上od分析

45.jpg

我们执行完这个test的函数后,他返回了一个十六进制的值,经过转换,可以知道他就是我们程序里写的6666,因此函数的返回值是放在eax的,
eax赋值为1或者其他,只要不是0就行,然后retn,返回即可
od中实际跟代码也相差不多,return 6666;只不过这个6666用eax寄存器保存了而已,
我们进入call eax这个汇编代码,然后进行赋值操作

46.jpg

530A3700    B8 66660000     MOV EAX,0x6666
530A3705    C3              RET
530A3706    90              NOP

在汇编中,我们写return是无法识别的,我们需要写成retn,或者ret都行



选择我们修改好的汇编代码,右键复制到可执行文件,然后选择所有修改,进行覆盖即可

47.jpg

50.jpg

49.jpg


24.jpg

评分

参与人数 53威望 +1 HB +158 THX +28 收起 理由
longge188 + 1 [吾爱汇编论坛52HB.COM]-软件反汇编逆向分析,软件安全必不可少!
流行格调 + 1 + 1 [吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩!
DDK4282 + 1 + 1 [吾爱汇编论坛52HB.COM]-感谢楼主热心分享,小小评分不成敬意!
459121520 + 1
后学真 + 1
消逝的过去 + 2
极速菜 + 1
冷亦飞 + 1
zyyujq + 1
车太震 + 1 [吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩!
kkk1l + 1
zg2600 + 1
侠客行 + 1
weiran324 + 1 [吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩!
fengyuan0128 + 1
ghostxu + 1 [吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守!
我是好人 + 1 [吾爱汇编论坛52HB.COM]-软件反汇编逆向分析,软件安全必不可少!
playboy + 2
小声点我布隆 + 1
ldljlzw + 1
夏520 + 1 + 1 [吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守!
我是用户名 + 1 [吾爱汇编论坛52HB.COM]-软件反汇编逆向分析,软件安全必不可少!
temp + 1
kickic + 1
hotD + 2 + 1
PDWORD + 1
成丰羽 + 1 [吾爱汇编论坛52HB.COM]-感谢楼主热心分享,小小评分不成敬意!
XiaoWeiSec + 1 [吾爱汇编论坛52HB.COM]-感谢楼主热心分享,小小评分不成敬意!
zxjzzh + 2 [吾爱汇编论坛52HB.COM]-软件反汇编逆向分析,软件安全必不可少!
sm5186 + 1 [吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守!
kalove + 1
3708272 + 1 + 1 [吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩!
Shin + 1
axigua + 1 + 1
hetao8003200 + 1
bnjzzheng + 1 [吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩!
wenrou999 + 1 [吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩!
baoyue + 1
阿桂哥 + 1 [吾爱汇编论坛52HB.COM]-软件反汇编逆向分析,软件安全必不可少!
CraftDeadMRC + 1
liugu0hai + 1 + 1 [快捷评语]--你将受到所有人的崇拜!
king51999 + 1 [快捷评语]--评分=感恩!简单却充满爱!感谢您的作品!
lies + 1
firstcmm + 1 [快捷评语]--你将受到所有人的崇拜!
Tian_52HB + 1
小G一小只 + 1 [快捷评语]--吃水不忘打井人,给个评分懂感恩!
mqlook + 1
HlccFu + 5 + 1 [快捷评语]--你将受到所有人的崇拜!
tingwei3 + 3 + 1 [快捷评语]--你将受到所有人的崇拜!
大彩笔 + 1 [快捷评语]--吃水不忘打井人,给个评分懂感恩!

查看全部评分

本帖被以下淘专辑推荐:

吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
 楼主| 白云点缀的蓝 发表于 2021-7-28 23:43 | 显示全部楼层

本帖最后由 白云点缀的蓝 于 2021-11-9 22:25 编辑

支持一下~~~
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
 楼主| 白云点缀的蓝 发表于 2021-7-28 23:05 | 显示全部楼层

@Shark恒 有些代码没有排版好,可以帮忙排版一下吗?谢谢
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
Shark恒 发表于 2021-7-29 10:46 | 显示全部楼层

好家伙,直接好家伙!讲解是够深入的,把CC断点的检测逻辑都讲到了,把指针也讲到了,确实很细致。赞一下,得给一个精华
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
大彩笔 发表于 2021-7-29 11:23 | 显示全部楼层

starry、星空 发表于 2021-7-28 23:43
DOC文档版:
https://starrysp.lanzoui.com/iODZnryy87a
这个就很好!论坛图片加载 不出来!
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
 楼主| 白云点缀的蓝 发表于 2021-7-29 12:50 | 显示全部楼层

大彩笔 发表于 2021-7-29 11:23
这个就很好!论坛图片加载 不出来!

恒大说在解决这个了,应该很快就能处理好吧
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
192939 发表于 2021-7-29 17:52 | 显示全部楼层

本帖最后由 192939 于 2021-7-29 18:58 编辑

辛苦楼主耐心讲了一大圈
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
192939 发表于 2021-7-29 18:49 | 显示全部楼层

试了下可以免登陆VIP,就是转换出来的语音没情感太机械
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
tingwei3 发表于 2021-7-29 21:17 | 显示全部楼层

好文,点赞了
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
lies 发表于 2021-7-31 00:29 | 显示全部楼层

谢谢教程,收藏
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

警告:本站严惩灌水回复,尊重自己从尊重他人开始!

1层
2层
3层
4层
5层
6层
7层
8层
9层
10层

免责声明

吾爱汇编(www.52hb.com)所讨论的技术及相关工具仅限用于研究学习,皆在提高软件产品的安全性,严禁用于不良动机。任何个人、团体、组织不得将其用于非法目的,否则,一切后果自行承担。吾爱汇编不承担任何因为技术滥用所产生的连带责任。吾爱汇编内容源于网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除。如有侵权请邮件或微信与我们联系处理。

站长邮箱:SharkHeng@sina.com
站长QQ:1140549900


QQ|RSS|手机版|小黑屋|帮助|吾爱汇编 ( 京公网安备11011502005403号 , 京ICP备20003498号-6 )|网站地图

Powered by Discuz!

吾爱汇编 www.52hb.com

快速回复 返回顶部 返回列表