首页 > 编程语言 >Win32汇编学习笔记02.RadAsm和联合编译

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

时间:2025-01-02 23:18:24浏览次数:1  
标签:02 sz NULL invoke lib Win32 RadAsm include inc

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:none

include windows.inc
include user32.inc
include kernel32.inc

;引入资源的头文件
include resource.inc

includelib user32.lib
includelib kernel32.lib

.data


.code

;打开窗口的过程函数
DialogProc proc  hwndDlg:HWND,    uMsg:UINT,   wParam:WPARAM,  lParam:LPARAM
    .IF uMsg == WM_COMMAND
        mov eax, wParam
        .IF ax == BTN_TEST
            ;调用弹窗的函数
            invoke MessageBox, NULL, NULL, NULL, MB_OK
        .ENDIF
    .ELSEIF uMsg == WM_CLOSE
        invoke EndDialog, hwndDlg, 0
    .ENDIF

    mov eax, FALSE  ;返回结果
    ret
DialogProc endp


WinMain proc hInstance:HINSTANCE 
  
    ;打开窗口函数  实例句柄必须给,不然找不到资源 
    invoke DialogBoxParam, hInstance, DLG_TEST, NULL, offset DialogProc, 0

    ret
WinMain endp



START:
    invoke GetModuleHandle, NULL
    invoke WinMain, eax
    invoke ExitProcess, 0

end START

使用C库

动态库使用

img

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

img

img

.386
.model flat, stdcall
option casemap:none

include windows.inc
include user32.inc
include kernel32.inc

include msvcrt.inc   ;c库头文件

includelib user32.lib
includelib kernel32.lib

includelib msvcrt.lib  ;c库实现文件


.data
    g_szFmt db "%s %d %08X", 0dh, 0ah, 0
    g_sz db "这是测试", 0
  
.code
main proc C

    invoke printf, offset g_szFmt, offset g_sz, 4096, 4096
    ;invoke strlen, offset g_sz
  
    ret
main endp


START:
    invoke main
    invoke ExitProcess, 0
end START

image.png

静态库使用

.386
.model flat, stdcall
option casemap:none

include windows.inc
include user32.inc
include kernel32.inc

includelib user32.lib
includelib kernel32.lib

includelib libc.lib    ;C库的静态库

public main           ;使用静态库必用要有 main函数

printf PROTO C :VARARG     ; 函数声明 VARARG  变参类型
strlen PROTO C :DWORD      ; 函数声明

.data
    g_szFmt db "%s %d %08X", 0dh, 0ah, 0
    g_sz db "这是测试", 0
  
.code
main proc C   ;调用约定必须是c

    invoke strlen, offset g_sz    ;调用c库函数
  
    ret
main endp


START:
    invoke main   ;调用main函数
    invoke ExitProcess, 0
end START

汇编和C的互调

ml /c /coff test.asm

link /subsystem:console test.obj
link /subsystem:windows test.obj

使用obj文件

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

c调用汇编的 obj文件
.386
.model flat, stdcall
option casemap:none

include windows.inc
include user32.inc
include kernel32.inc

includelib user32.lib
includelib kernel32.lib


.data
    g_szFmt db "%s %d %08X", 0dh, 0ah, 0
    g_sz db "这是测试", 0
  
.code

TestFunc PROC  sz:dword
    invoke MessageBox,NULL,sz,offset  g_sz,MB_OK  ;调用弹窗,显示传入的字符串
    ret
TestFunc ENDP

;防止程序把  START 当做程序入口,直接退出程序
;START:
    ;invoke ExitProcess,0   ;退出程序
;end START

end  

查看 生成的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:none

include windows.inc
include user32.inc
include kernel32.inc

includelib user32.lib
includelib kernel32.lib

Func proto c sz:DWORD  ;将函数声明改成汇编形式

.data
    g_szFmt db "%s %d %08X", 0dh, 0ah, 0
    g_sz db "这是测试", 0
  
.code

TestFunc PROC  sz:dword
    invoke MessageBox,NULL,sz,offset  g_sz,MB_OK
    ret
TestFunc ENDP

end


把汇编生成的 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:none

include windows.inc
include user32.inc
include kernel32.inc

includelib user32.lib
includelib kernel32.lib


Func proto c sz:DWORD  ;将函数声明改成汇编形式


.data
    g_szFmt db "%s %d %08X", 0dh, 0ah, 0
    g_sz db "这是测试", 0
  
.code

;调用 c 的obj文件必须有,虽然没什么用
main proc c
    ret
main endp

TestFunc PROC  sz:dword
    invoke MessageBox,NULL,sz,offset  g_sz,MB_OK
    ret
TestFunc ENDP

START:
    invoke Func, offset g_sz
    invoke 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:none

include windows.inc
include user32.inc
include kernel32.inc

includelib user32.lib
includelib kernel32.lib

Func proto c sz:DWORD  ;将函数声明改成汇编形式

.data
    g_szFmt db "%s %d %08X", 0dh, 0ah, 0
    g_sz db "这是测试", 0
  
.code

;调用 c 的obj文件必须有,虽然没什么用
main proc c
    ret
main endp

TestFunc PROC  sz:dword
    invoke MessageBox,NULL,sz,offset  g_sz,MB_OK
    ret
TestFunc ENDP

START:
    invoke Func, offset g_sz
    invoke 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:none
    
    include windows.inc
    include user32.inc
    include kernel32.inc
    
    includelib  MyDll.lib ;导入lib库
    
    includelib user32.lib
    includelib kernel32.lib
    
    Func proto c sz:DWORD  ;将函数声明改成汇编形式
    
    .data
        g_szFmt db "%s %d %08X", 0dh, 0ah, 0
        g_sz db "这是测试", 0
    
    .code
    
    ;调用 c 的obj文件必须有,虽然没什么用
    main proc c
        ret
    main endp
    
    TestFunc PROC  sz:dword
        invoke MessageBox,NULL,sz,offset  g_sz,MB_OK
        ret
    TestFunc ENDP
    
    START:
        invoke Func, offset g_sz
        invoke ExitProcess,0   ;退出程序
    end START
    

    img

    img

    C使用汇编的DLL

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

    .386
    .model flat, stdcall
    option casemap:none
    
    include windows.inc
    include user32.inc
    include kernel32.inc
    
    includelib user32.lib
    includelib kernel32.lib
    
    .data
        g_sz db "这是测试", 0
    
    .code 
    TestFunc proc sz:DWORD
        invoke MessageBox, NULL, sz, offset g_sz, MB_OK 
        ret
    TestFunc endp
    
    ; dll 必须要有 DllMain 
    DllMain proc hinstDLL:HINSTANCE,  fdwReason:DWORD, lpvReserved:LPVOID
    
        mov eax, TRUE
        ret
    DllMain endp
    
    end 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, n0
        mov n0, 10

        push MB_OK
        push sz
        push NULL
        push NULL
        call MessageBoxA

        mov eax, size n
        mov eax, length n
        mov 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, eax
        mov eax, n
        mov eax, n0
        mov n0, 10

        push MB_OK
        push sz
        push NULL
        push NULL
        call MessageBoxA   //汇编里面调函数  ,宏汇编是无法使用的

        //使用伪指令
        mov eax, size n
        mov eax, length n
        mov eax, offset wWinMain
    }
}

//裸函数
__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
    }
}

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 } } 

作业

标签:02,sz,NULL,invoke,lib,Win32,RadAsm,include,inc
From: https://www.cnblogs.com/weiyuanzhang/p/18648915

相关文章

  • 大普RTC代理商INS58563、INS5T8025、INS5710
    INS58563是大普通信新推出的一款晶体分离式、低功耗实时时钟/日历芯片,可以提供年、月、周、日、时、分、秒计时,支持可编程时钟输出、中断输出、低压检测、定时器、告警等多功能,完成各种复杂的定时服务。所有地址和数据通过I2C总线串联传输,最高速率可达400kbps。关键特性:---外置......
  • Diary - 2025.01.02
    下午去干了一下AtcoderAGC070A。感觉脑子有点爆掉了,但好在我觉得我是理解了。感觉大致还是从小学时候的\(1/7=0.141857\cdots\)这个\(142857\)的回马灯数(是这么叫的?)入手。发现这样子只需要拼出一个\(142857142857\)就能满足\(1\sim6\)的限制。考虑这是为什么,能......
  • 日常训练2025-1-2
    日常训练2025-1-2D.Digitalstringmaximizationrating:1300https://codeforces.com/contest/2050/problem/D思路:找trick+暴力根据题意,一个数值为i的数最多向左移动i步。而最大的数为9,也就是说对于一个位置x,他的值只可能来自于\([x,x+9]\)这个范围,更远的......
  • 工作感受月记(202501月)
    2025年01月02号新年第一个工作日。今日工作事项:1/与basf的mason电话沟通,讨论containerapp的默认域名问题,最后发现对外开放访问的app也是需要验证域名所有权的。2/与宁德时代的yousong沟通,讨论appservice的自动缩放问题,app执行的是webjob,预计自动缩放功能不实用。只有role......
  • 【信阳师范大学】计算机导论2023年期末考试
    信阳师范大学计算机导论2023年期末考试更多期末考试资料请查看博客:https://blog.x1a0yu.top/第3讲:计算与计算的本质(简答)一.简答题(共9题,90分)1.(简答题,10分)简述计算机的基本组成部分,并说明它们的功能正确答案:计算机的基本组成部分包括输入设备、输出设备、中央......
  • 2024165读书笔记|《飞花令·合》——人生飘忽百年内,且须酣畅万古情
    2024165读书笔记|《飞花令·合》——人生飘忽百年内,且须酣畅万古情屈原班婕妤曹植刘绘卢思道卢照邻苏味道刘希夷李白高适杜甫司空曙白居易温庭筠韦庄窦叔向张泌林逋柳永晏殊欧阳修李觏舒亶秦观陈瓘李清照陆游辛弃疾姜夔蒋捷吴伟业纳兰性德张惠言邓廷桢《飞花令·合》......
  • 再见2024,你好2025
    再见2024,你好20251月2月3月4月5~10月11~12月一些收获读书跑步工作为了让这篇博客不那么平淡,一句话可以总结为:平平无奇的琐碎,没有亮点成果。也可以数字化概述:涨了1万+粉,赚了10万+,跑步300+公里,读完300+本书,又活了1年~似乎没觉得时间的流逝,这一年就咣咣咣的马上要过完......
  • 2025年第十届机械结构与智能材料国际会议
    ICMSSM2025第十届机械结构与智能材料国际会议会议时间:2025年5月17-19日会议地点:泰国,曼谷https://www.icmssm.org/2025年第十届机械结构与智能材料国际会议(ICMSSM2025)将于2025年5月17-19日在泰国曼谷召开。作为过去九年在厦门、吉隆坡、南京、深圳、西安、越南、长沙、......
  • 2024.12.30
    《程序员修炼之道》这本书为程序员的成长提供了全方位的指引。读完它,我对编程有了全新的认识。书中强调了代码的质量和可维护性。它指出编写代码并非仅仅实现功能,更要注重代码的整洁与高效。例如,通过编写简洁的代码,不仅能提高代码的可读性,还能减少潜在的错误。书中提到的“代码......
  • 2024.12.29
    《代码大全2》是一本极具价值的编程书籍,它为软件开发人员提供了丰富的知识和经验。阅读完这本书,我深受启发。书中对代码的各种方面进行了深入的探讨,从代码的设计到具体的实现,都给出了详细的指导。它强调了代码的可读性和可维护性,这让我明白写代码不仅仅是实现功能,更要注重代码的......