Win32汇编学习笔记02.RadAsm和联合编译

news/2025/1/6 18:43:48/文章来源:https://www.cnblogs.com/weiyuanzhang/p/18648915

https://bpsend.net/thread-151-1-1.html

汇编使用资源

汇编使用资源的方式和C的一样,也是把资源文件 rc 编译成 res 再链接进去,汇编没有自己的资源编辑器,需要借助 vc6.0或者 vs

主要是把 头文件 .h 转化为对应的 .inc

使用vc6.0建立资源文件

img

img

img

img

img

img

img

用vs建立资源文件

  1. 新建一个桌面向导

img

img

生成文件之后,再打开 rc 文件,生成为

img

img

编译链接文件时要讲资源文件加进去

ml /c /coff %1.asm
if errorlevel 1 goto err
rc %1.rc   ;如果用的是是vs自己生成的 res文件,就不需要
if errorlevel 1 goto err
link /subsystem:windows %1.obj %1.res
if errorlevel 1 goto err
OllyICE.exe %1.exe
:err
pause

img

汇编代码

.386
.model flat, stdcall
option casemap:noneinclude windows.inc
include user32.inc
include kernel32.inc;引入资源的头文件
include resource.incincludelib user32.lib
includelib kernel32.lib.data.code;打开窗口的过程函数
DialogProc proc  hwndDlg:HWND,    uMsg:UINT,   wParam:WPARAM,  lParam:LPARAM.IF uMsg == WM_COMMANDmov eax, wParam.IF ax == BTN_TEST;调用弹窗的函数invoke MessageBox, NULL, NULL, NULL, MB_OK.ENDIF.ELSEIF uMsg == WM_CLOSEinvoke EndDialog, hwndDlg, 0.ENDIFmov eax, FALSE  ;返回结果ret
DialogProc endpWinMain proc hInstance:HINSTANCE ;打开窗口函数  实例句柄必须给,不然找不到资源 invoke DialogBoxParam, hInstance, DLG_TEST, NULL, offset DialogProc, 0ret
WinMain endpSTART:invoke GetModuleHandle, NULLinvoke WinMain, eaxinvoke ExitProcess, 0end START

使用C库

动态库使用

img

可以看出,C库函数声明 在 msvcrt.inc中 并在前面加 crt_

img

img

.386
.model flat, stdcall
option casemap:noneinclude windows.inc
include user32.inc
include kernel32.incinclude msvcrt.inc   ;c库头文件includelib user32.lib
includelib kernel32.libincludelib msvcrt.lib  ;c库实现文件.datag_szFmt db "%s %d %08X", 0dh, 0ah, 0g_sz db "这是测试", 0.code
main proc Cinvoke printf, offset g_szFmt, offset g_sz, 4096, 4096;invoke strlen, offset g_szret
main endpSTART:invoke maininvoke ExitProcess, 0
end START

image.png

静态库使用

.386
.model flat, stdcall
option casemap:noneinclude windows.inc
include user32.inc
include kernel32.incincludelib user32.lib
includelib kernel32.libincludelib libc.lib    ;C库的静态库public main           ;使用静态库必用要有 main函数printf PROTO C :VARARG     ; 函数声明 VARARG  变参类型
strlen PROTO C :DWORD      ; 函数声明.datag_szFmt db "%s %d %08X", 0dh, 0ah, 0g_sz db "这是测试", 0.code
main proc C   ;调用约定必须是cinvoke strlen, offset g_sz    ;调用c库函数ret
main endpSTART:invoke main   ;调用main函数invoke ExitProcess, 0
end START

汇编和C的互调

ml /c /coff test.asmlink /subsystem:console test.obj
link /subsystem:windows test.obj

使用obj文件

从语法上来将,c和汇编的语法是相互不兼容的,所以想在源码上进行相互间的调用是不可能的事情, 所以只能退而求其次 使用obj文件, 把 c 的 obj文件给汇编去用,把 汇编的 obj 文件 给 c 去用

c调用汇编的 obj文件
.386
.model flat, stdcall
option casemap:noneinclude windows.inc
include user32.inc
include kernel32.incincludelib user32.lib
includelib kernel32.lib.datag_szFmt db "%s %d %08X", 0dh, 0ah, 0g_sz db "这是测试", 0.codeTestFunc PROC  sz:dwordinvoke MessageBox,NULL,sz,offset  g_sz,MB_OK  ;调用弹窗,显示传入的字符串ret
TestFunc ENDP;防止程序把  START 当做程序入口,直接退出程序
;START:;invoke ExitProcess,0   ;退出程序
;end STARTend  

查看 生成的obj 文件, 我们的 函数的名字

img

调用

  1. 新建一个 32位的桌面应用程序

img

  1. 把obj文件复制到工程目录下
  2. 再导入.bobj文件

img

img

  1. 去掉预编译头

img

extern "C" void __stdcall TestFunc(char* sz);   //对函数进行声明,注意调用约定int main(int argc, char* argv[])
{TestFunc("你好");   //调用汇编obj里面的函数printf("Hello World!\n");return 0;
}

img

用vs调用 汇编obj
.386
.model flat, stdcall
option casemap:noneinclude windows.inc
include user32.inc
include kernel32.incincludelib user32.lib
includelib kernel32.libFunc proto c sz:DWORD  ;将函数声明改成汇编形式.datag_szFmt db "%s %d %08X", 0dh, 0ah, 0g_sz db "这是测试", 0.codeTestFunc PROC  sz:dwordinvoke MessageBox,NULL,sz,offset  g_sz,MB_OKret
TestFunc ENDPend

把汇编生成的 obj 文件 放入项目

image.png

image.png

image.png

汇编使用C语言的 obj

1新建一个c的源文件

image.png

2取消预编译头

image.png

#include <windows.h>void Func(char* sz)
{MessageBox(NULL,sz,"这是c函数",MB_OK);
}

img

img

把 obj文件放到汇编代码同目录

.386
.model flat, stdcall
option casemap:noneinclude windows.inc
include user32.inc
include kernel32.incincludelib user32.lib
includelib kernel32.libFunc proto c sz:DWORD  ;将函数声明改成汇编形式.datag_szFmt db "%s %d %08X", 0dh, 0ah, 0g_sz db "这是测试", 0.code;调用 c 的obj文件必须有,虽然没什么用
main proc cret
main endpTestFunc PROC  sz:dwordinvoke MessageBox,NULL,sz,offset  g_sz,MB_OKret
TestFunc ENDPSTART:invoke Func, offset g_szinvoke ExitProcess,0   ;退出程序
end START

img

解决办法,把 vs 或者vc6的 lib 加入环境变量

img

汇编使用 vs 的 obj

在vs项目中添加一个 Func.c 文件 代码如下,生成解决方案

#include <windows.h>void Func(char* sz)
{MessageBox(NULL, sz, "这是c函数", MB_OK);
}

把obj文件放到同目录

.386
.model flat, stdcall
option casemap:noneinclude windows.inc
include user32.inc
include kernel32.incincludelib user32.lib
includelib kernel32.libFunc proto c sz:DWORD  ;将函数声明改成汇编形式.datag_szFmt db "%s %d %08X", 0dh, 0ah, 0g_sz db "这是测试", 0.code;调用 c 的obj文件必须有,虽然没什么用
main proc cret
main endpTestFunc PROC  sz:dwordinvoke MessageBox,NULL,sz,offset  g_sz,MB_OKret
TestFunc ENDPSTART:invoke Func, offset g_szinvoke ExitProcess,0   ;退出程序
end START

此时去编译链接项目 会有一大堆 外部符号找不到, 这些 库是vs 的 ,解决办法是把这些库加进来,或者使用 vs 的命令提示符.很麻烦,还要关掉一堆的检查,最好的方法使用dll

使用dll

dll的接口是很标准的,从dll出现为止,基本没变过

汇编使用 C 的 dll
  1. 用vs创建一个动态链接库

    // dllmain.cpp : 定义 DLL 应用程序的入口点。
    #include "pch.h"#include <windows.h>extern "C" void Func(char* sz)   //声明函数和调用约定
    {MessageBoxA(NULL, sz, "这是c函数", MB_OK);
    }BOOL APIENTRY DllMain(HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved
    )
    {switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;}return TRUE;
    }

    导出函数

    img

    把生成 的 dll 和 lib 文件 放到汇编同目录下

    .386
    .model flat, stdcall
    option casemap:noneinclude windows.inc
    include user32.inc
    include kernel32.incincludelib  MyDll.lib ;导入lib库includelib user32.lib
    includelib kernel32.libFunc proto c sz:DWORD  ;将函数声明改成汇编形式.datag_szFmt db "%s %d %08X", 0dh, 0ah, 0g_sz db "这是测试", 0.code;调用 c 的obj文件必须有,虽然没什么用
    main proc cret
    main endpTestFunc PROC  sz:dwordinvoke MessageBox,NULL,sz,offset  g_sz,MB_OKret
    TestFunc ENDPSTART:invoke Func, offset g_szinvoke ExitProcess,0   ;退出程序
    end START
    

    img

    img

    C使用汇编的DLL

    汇编也可以写成dll .注意字符集

    .386
    .model flat, stdcall
    option casemap:noneinclude windows.inc
    include user32.inc
    include kernel32.incincludelib user32.lib
    includelib kernel32.lib.datag_sz db "这是测试", 0.code 
    TestFunc proc sz:DWORDinvoke MessageBox, NULL, sz, offset g_sz, MB_OK ret
    TestFunc endp; dll 必须要有 DllMain 
    DllMain proc hinstDLL:HINSTANCE,  fdwReason:DWORD, lpvReserved:LPVOIDmov eax, TRUEret
    DllMain endpend DllMain   ;DllMain一般作为函数入口点

新建一个def 文件导出函数

image.png

image.png

此时dll中并没有导出函数,因为没有告诉链接器去用它

image.png

image.png

image.png

这个dll就可以给 c程序用了

把 生成 的 dll 和lib 放到正确位置

#include "framework.h"
#include "Project2.h"#pragma comment(lib, "asmdll.lib")  使用生成的 lib库
extern "C" void __stdcall TestFunc(char* sz);int APIENTRY wWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPWSTR    lpCmdLine,_In_ int       nCmdShow)
{TestFunc((char*)"你好");
}

img

内联汇编

内联

在c,c++中写汇编代码 ,在内联汇编中,宏汇编是无法使用的,但是部分伪指令是可以用的,而且只有 32位程序可以写,64位程序是无法内联汇编的

当我们想把某个函数注入到对方进程里面,这样就要求我们的代码是纯汇编的,因为一旦用到vs的代码,vs就会加一堆检查

格式: 关键字 __asm

 __asm         mov eax, eax__asm        mov eax, n__asm {mov eax, n0mov n0, 10push MB_OKpush szpush NULLpush NULLcall MessageBoxAmov eax, size nmov eax, length nmov eax, offset wWinMain}

img

// Project2.cpp : 定义应用程序的入口点。
//#include "framework.h"
#include "Project2.h"
#pragma comment(lib, "asmdll.lib")
extern "C" void __stdcall TestFunc(char* sz);void TestAsm(int n, char* sz)
{int n0 = 9;__asm {mov eax, eaxmov eax, nmov eax, n0mov n0, 10push MB_OKpush szpush NULLpush NULLcall MessageBoxA   //汇编里面调函数  ,宏汇编是无法使用的//使用伪指令mov eax, size nmov eax, length nmov eax, offset wWinMain}
}//裸函数
__declspec(naked) void Test(int n, char* sz)
{//裸函数申请栈空间__asm{push ebpmov ebp, espsub esp, 0x40};裸函数不允许初始化变量int n0;float f0;n0 = 9;f0 = 3.14f;if (n0 == n){MessageBoxA(NULL, NULL, NULL, NULL);}__asm{mov esp, ebppop ebpret}
}int APIENTRY wWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPWSTR    lpCmdLine,_In_ int       nCmdShow)
{Test(99, (char*)"hello world");TestAsm(99, (char*)"hello world");//TestFunc((char*)"你好");return 0;
}

裸函数 __declspec(naked)

正常一个空函数什么都不写.都回会有一些初数化操作,但是如果不要,可以声明 它是一个裸函数,就不会帮其生成代码,需要自己去生成

 
//裸函数 __declspec(naked) void Test(int n, char* sz) { __asm { push ebp mov ebp, esp sub esp, 0x40 } int n0; float f0; n0 = 9; f0 = 3.14f; if (n0 == n) { MessageBoxA(NULL, NULL, NULL, NULL); } __asm { mov esp, ebp pop ebp ret } } 

作业

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/863137.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

判断方法的使用范围20250102

判断方法的使用范围20250102package com.oop.demo01;public class Student {public static int add(int a, int b) { //public 类下的public的静态方法return a+b;}static int sub(int a, int b) { //public类 非public的静态方法return a-b;}public int devide(int a, int…

火绒(杀毒软件) v6.0.1.4 正式版

火绒这个软件很受极客们的欢迎,是一款小巧轻便的杀毒软件,功能也很丰富,运行安静,使用方便。也是果核很喜欢的一款杀毒软件,其火绒剑是一款非常强大的系统监控和调试工具,能帮助有电脑底层基础的用户快速排查问题。获取地址:https://www.dmjf.top/2255.html

Android AdGuard(广告拦截) v4.7.163 高级版

Adguard为你提供了一个可靠的、可管理的保护,就没有你们的参与滤波器加载网页。adguard移除所有烦人的广告,阻止危险网站的加载,也不会允许任何人在网上跟踪你的活动。获取地址:https://www.dmjf.top/2690.html

Windows编译QT6.4.3及使用

1. 下载QT6.4.3源码,并解压 Index of /archive/qt/6.4/6.4.3/singlehttps://download.qt.io/archive/qt/6.4/6.4.3/single/ 2.安装环境 * CMake 3.18 or later* Perl 5.8 or later* Python 2.7 or later* C++ compiler supporting the C++17 standard 3.打开windows的cmd cd…

ESP32-S3-N16R8在platformio中的开发板设置

前言 platformio现有的板子库里面没有ESP32-S3-N16R8(8MB PSRAM + 16MB FLASH)的开发板模型,直接强行套用,要么就是解锁不了8MB PSRAM,要么就下载后运行不起来。一、选用esp32-s3-devkitc-1开发板 先选用esp32-s3-devkitc-1作为开发板模型,点击Finish后务必耐心等待。 二…

《docker基础篇:8.Docker常规安装简介》包括:docker常规安装总体步骤、安装tomcat、安装mysql、安装redis

《docker基础篇:8.Docker常规安装简介》包括:docker常规安装总体步骤、安装tomcat、安装mysql、安装redis@目录8.Docker常规安装简介8.1 docker常规安装总体步骤8.2安装tomcat8.3 安装mysql8.3.1 docker hub上面查找mysql镜像8.3.2 从docker hub上(阿里云加速器)拉取mysql镜像…

Elasticsearch VS Easysearch 性能测试

压测环境 虚拟机配置 使用阿里云上规格:ecs.u1-c1m4.4xlarge,PL2: 单盘 IOPS 性能上限 10 万 (适用的云盘容量范围:461GiB - 64TiB)vCPU 内存 (GiB) 磁盘(GB) 带宽(Gbit/s) 数量16 64 500 5000 24Easysearch 配置 7 节点集群,版本:1.9.0实例名 内网 IP 软件 vCPU JVM 磁…

win10/win11 用 ncpa.cpl 命令快速打开网络连接

前言:Win11系统配置网络适配器好费劲的,每次都要在设置找半天 得,直接来,快捷键安排1、开始 -> 运行 Win + R 弹出 运行 窗口2、输入命令 ncpa.pcl并回车 3、见证奇迹QQ:1061767621 Q群:215481318

基于爬山法MPPT最大功率跟踪算法的光伏发电系统simulink建模与仿真

1.课题概述 基于爬山法MPPT最大功率跟踪算法的光伏发电系统simulink建模与仿真。2.系统仿真结果3.核心程序与模型 版本:MATLAB2022a 4.系统原理简介最大功率点跟踪(Maximum Power Point Tracking, MPPT)是光伏发电系统中至关重要的技术,用于确保光伏电池在其工作条件下输出最…

网络_网络分层模型和应用协议

本文主要介绍了网络的分层模型和应用层的协议,分层模型有四层、七层、五层这几种模型,应用层协议主要涉及 URL 和 HTTP,并且介绍了请求和响应以及他们的行、头、体网络分层模型和应用协议 分层模型 为了解决复杂问题往往分层 经过不断的演化,网络最终形成了五层模型:MAC像…

1.2 可压缩流:激波和膨胀扇

1.2 可压缩流:激波和膨胀扇 前言 欢迎观看《Bang Dream! Ave mujica》,一部超好看的少女乐队动漫,从2025.1.2开始,每周四晚10点更新。 哇嘎利马斯 大量玩梗注意 AA笔记主要参考刘永学主编《空气动力学》,讲的物理概念很清晰易懂,推荐给大家。 扰动的传播 接下来我们讨论扰…

使用ClosedXML实现Excel导入导出

使用ClosedXML实现Excel导入导出 写在开头 游览Dotnet 基金会中的项目时,发现了这个库,Github 链接,它的性能非常好,详细见下图话不多说,直接上代码吧! 导出 后端: public static byte[] Output<T>(List<T> data, string sheetName) {using var workbook = …