win32汇编编程

合集下载

汇编教程Win32调试API(1)

汇编教程Win32调试API(1)

在本教程中,我们将学习Win32提供给开发者的用于调试的原语. 在教程的结尾,我们将学习如何调试一个进程.理论:Win32有一些供程序员使用的API,它们提供相当于调试器的功能. 他们被称作Win32调试API(或原语).利用这些API,我们可以:加载一个程序或捆绑到一个正在运行的程序上以供调试获得被调试的程序的低层信息,例如进程ID,进入地址,映像基址等.当发生与调试有关的事件时被通知,例如进程/线程的开始/结束, DLL的加载/释放等.修改被调试的进程或线程简而言之,我们可以用这些API写一个简单的调试器.由于这个题目有些过大,我把它分为几部分,而本教程就是它的第一部分.在本教程中,我将讲解一些基本概念及Win32调试AP I的大致框架.使用Win32调试API的步骤如下:创建一个进程或捆绑到一个运行中的进程上. 这是使用Win32调试API的第一步.由于我们的程序要扮演调试器的角色,我们要找一个供调试的程序.一个被调试的程序被称为de buggee.可以通过以下两种方式获得debuggee:通过CreateProcess创建debuggee进程.为了创建被调试的进程,必须指定DEBUG_PROC ESS标志.这一标志告诉Windows我们要调试该进程. 当debuggee中发生重要的与调试有关的事件(调试事件)时,Windows 会向我们的程序发送通知.debuggee会立即挂起以等待我们的程序准备好.如果debuggee还创建了子进程,Windows还会为每个子进程中的调试事件向我们的程序发送通知.这一特性通常是不必要的.我们可以通过指定DEBUG_ONLY_THIS_PROC ESS与 DEBUG_PROCESS的组合标志来禁止它.我们也可以用 DebugActiveProcess标志捆绑到一个运行中的进程上.等待调试事件. 在获得了一个debuggee进程后,debuggee的主线程被挂起,这种状况将持续到我们的程序调用WaitForDebugEvent为止.这个函数和其他的WaitForXXX函数相似,比如说,它阻塞调用线程直到等待的事件发生.对这个函数来说, 它等待由Windows发送的调试事件.下面是它的定义:WaitForDebugEvent proto lpDebugEvent:DWORD, dwMilliseconds:DWORDlpDebugEvent is the address of a DEBUG_EVENT这个结构将被填入关于debuggee中发生的调试事件的信息.dwMilliseconds 该函数等待调试事件的时间,以毫秒为单位.如果这段时间没有调试事件发生, WaitForDebugEvent返回调用者.另一方面,如果将该参数指定为 INFINITE 常数,函数将一直等待直到调试事件发生.现在我们看一下DEBUG_EVENT 结构.DEBUG_EVENT STRUCTdwDebugEventCode dd ?dwProcessId dd ?dwThreadId dd ?u DEBUGSTRUCT <>DEBUG_EVENT ENDSdwDebugEventCode 该值指定了等待发生的调试事件的类型.因为有很多种类型的事件发生,我们的程序要检查该值,知道要发生事件的类型并做出响应. 该值可能的取值如下:取值含义CREATE_PROCESS_DEBUG_EVENT 进程被创建.当debuggee进程刚被创建(还未运行) 或我们的程序刚以DebugActiveProcess被捆绑到一个运行中的进程时事件发生. 这是我们的程序应该获得的第一个事件.EXIT_PROCESS_DEBUG_EVENT 进程退出.CREATE_THEAD_DEBUG_EVENT 当一个新线程在deuggee进程中创建或我们的程序首次捆绑到运行中的进程时事件发生.要注意的是当debugge的主线程被创建时不会收到该通知.EXIT_THREAD_DEBUG_EVENT debuggee中的线程退出时事件发生.debugee的主线程退出时不会收到该通知.我们可以认为debuggee的主线程与debugge进程是同义词. 因此, 当我们的程序看到CREATE_PROCESS_DEBUG_EVENT标志时,对主线程来说,就是CREATE_THREAD_DE BUG_EVENT标志.LOAD_DLL_DEBUG_EVENT debuggee装入一个DLL.当PE装载器第一次分解指向DLL的链接时,我们将收到这一事件. (当调用CreateProcess装入 debuggee时)并且当debuggee调用LoadLibrary时也会发生.UNLOAD_DLL_DEBUG_EVENT 一个DLL从debuggee中卸载时事件发生.EXCEPTION_DEBUG_EVENT 在debuggee中发生异常时事件发生. 注意: 该事件仅在debu ggee开始它的第一条指令之前发生一次.异常实际上是一个调试中断(int 3h).如果想恢复debuggee事,以 DBG_CONTINUE 标志调用ContinueDebugEvent 函数. 不要使用DBG_EXCEPT ION_NOT_HANDLED 标志否则debuggee会在NT下拒绝运行(Win98下运行得很好).OUTPUT_DEBUG_STRING_EVENT 当debuggee调用DebugOutputString函数向我们的程序发送消息字符串时该事件发生.RIP_EVENT 系统调试发生错误dwProcessId 和dwThreadId发生调试事件的进程和线程Id.我们可以用这些值作为我们感兴趣的进程或线程的标志符.记住如果我们使用CreateProcess来装载debuggee,我们仍可在PROCESS_INFO结构中获得debuggee的进程和线程.我们可以用这些值来区别调试事件是发生在debuggee中还是它的子进程中(当没有指定 DEBUG_ONLY_THIS_PROCESS 标志时).u 是一个联合,包含了调试事件的更多信息.根据上面dwDebugEventCode的不同,它可以是以下结构:dwDebugEventCode u的解释CREATE_PROCESS_DEBUG_EVENT 名为CreateProcessInfo的CREATE_PROCESS_DEBUG_INF O结构EXIT_PROCESS_DEBUG_EVENT 名为ExitProcess的EXIT_PROCESS_DEBUG_INFO结构CREATE_THREAD_DEBUG_EVENT 名为CreateThread的CREATE_THREAD_DEBUG_INFO结构EXIT_THREAD_DEBUG_EVENT 名为ExitThread的EXIT_THREAD_DEBUG_EVENT 结构LOAD_DLL_DEBUG_EVENT 名为LoadDll的LOAD_DLL_DEBUG_INFO 结构UNLOAD_DLL_DEBUG_EVENT 名为UnloadDll的UNLOAD_DLL_DEBUG_INFO结构EXCEPTION_DEBUG_EVENT 名为Exception的EXCEPTION_DEBUG_INFO结构OUTPUT_DEBUG_STRING_EVENT 名为DebugString的OUTPUT_DEBUG_STRING_INFO 结构RIP_EVENT 名为RipInfo的RIP_INFO 结构我不会在这一个教程里讲所有这些结构的细节,这里只详细讲一下CREATE_PROCESS_DE BUG_INFO 结构.假设我们的程序调用了WaitForDebugEvent函数并返回,我们要做的第一件事就是检查dwDebugEventCode中的值来看debuggee进程中发生了那种类型的调试事件.比如说,如果d wDebugEventCode的值为 CREATE_PROCESS_DEBUG_EVENT,就可认为u的成员为CreateProce ssInfo 并用u.CreateProcessInfo来访问.在我们的程序中做对调试事件的响应. 当WaitForDebugEvent 返回时,这意味着在deb uggee进程中发生了调试事件或者发生了超时.所以我们的程序要检查dwDebugEventCode 来作出适当的反应.这里有些象处理Windows消息:由用户来选择和忽略消息.继续运行debuggee. 当调试事件发生时, Windows挂起了debuggee,所以当我们处理完调试事件,还要让debuggee继续运行.调用ContinueDebugEvent 函数来完成这一过程.ContinueDebugEvent proto dwProcessId:DWORD, dwThreadId:DWORD, dwContinueSta tus:DWORD该函数恢复由于调试事件而挂起的线程.dwProcessId和dwThreadId是要恢复的线程的进程ID和线程ID,通常这两个值从 DEB UG_EVENT结构的dwProcessId 和dwThreadId成员获得.dwContinueStatus显示了如何继续报告调试事件的线程.可能的取值有两个: DBG_CON TINUE 和DBG_EXCEPTION_NOT_HANDLED. 对大多数调试事件,这两个值都一样:恢复线程.唯一的例外是EXCEPTION_DEBUG_EVENT,如果线程报告发生了一个异常调试事件,这意味着在d ebuggee的线程中发生了一个异常.如果指定了DBG_CONTINUE,线程将忽略它自己的异常处理部分并继续执行.在这种情况下,我们的程序必须在以DBG_CONTINUE恢复线程之前检查并处理异常,否则异常将生生不息地不断发生....如果我们指定了 DBG_EXCEPTION_NOT_HANDL ED值,就是告诉Windows我们的程序并不处理异常:Windows将使用debuggee的默认异常处理函数来处理异常.总而言之,如果我们的程序没有考虑异常,而调试事件又指向debuggee进程中的一个异常的话,就应调用含DBG_CONTINUE标志的ContinueDebugEvent函数.否则,我们的程序就必须以DBG_EXCEPTION_NOT_HANDLED调用 ContinueDebugEvent.但在下面这种情况下必须使用DBG_CONTINUE标志:第一个在ExceptionCode成员中有值EXCEPTION_BREAKPOINT的 EXC EPTION_DEBUG_EVENT事件.当debuggee开始执行它的第一条指令时,我们的函数将接受到异常调试事件.它事实上是一个调试中断(int 3h).如果我们以DBG_EXCEPTION_NOT_HANDLED 调用ContinueDebugEvent 来响应调试事件, Windows NT会拒绝执行debuggee(因为它没有异常处理).所以在这种情况下,要用DBG_CONTINUE标志告诉Windows我们希望该线程继续执行.继续上面的步骤循环直到debuggee进程退出. 我们的程序必须在一个很象消息循环的无限循环中直到debuggee结束.该循环大体如下:.while TRUEinvoke WaitForDebugEvent, addr DebugEvent, INFINITE.break .if DebugEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT<调试事件处理>invoke ContinueDebugEvent, DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_E XCEPTION_NOT_HANDLED.endw就是说,当开始调试程序时,我们的程序不能和debuggee分开直到它结束.我们再来总结一下这些步骤:创建一个进程或捆绑我们的程序到运行中的进程上.等待调试事件响应调试事件.继续执行debuggee.继续这一无尽循环直到debuggee进程结束例子:这个例子调试一个win32程序并显示诸如进程句柄,进程Id,映象基址等..386.model flat,stdcalloption casemap:noneinclude \masm32\include\windows.incinclude \masm32\include\kernel32.incinclude \masm32\include\comdlg32.incinclude \masm32\include\user32.incincludelib \masm32\lib\kernel32.libincludelib \masm32\lib\comdlg32.libincludelib \masm32\lib\user32.lib.dataAppName db "Win32 Debug Example no.1",0ofn OPENFILENAME <>FilterString db "Executable Files",0,"*.exe",0db "All Files",0,"*.*",0,0ExitProc db "The debuggee exits",0NewThread db "A new thread is created",0EndThread db "A thread is destroyed",0ProcessInfo db "File Handle: %lx ",0dh,0Ahdb "Process Handle: %lx",0Dh,0Ahdb "Thread Handle: %lx",0Dh,0Ahdb "Image Base: %lx",0Dh,0Ahdb "Start Address: %lx",0.data?buffer db 512 dup(?)startinfo STARTUPINFO <>pi PROCESS_INFORMATION <>DBEvent DEBUG_EVENT <>.codestart:mov ofn.lStructSize,sizeof ofnmov ofn.lpstrFilter, offset FilterStringmov ofn.lpstrFile, offset buffermov ofn.nMaxFile,512mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_E XPLORER or OFN_HIDEREADONLYinvoke GetOpenFileName, ADDR ofn.if eax==TRUEinvoke GetStartupInfo,addr startinfoinvoke CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, DEBUG_PROCESS+ DEBU G_ONLY_THIS_PROCESS, NULL, NULL, addr startinfo, addr pi.while TRUEinvoke WaitForDebugEvent, addr DBEvent, INFINITE.if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENTinvoke MessageBox, 0, addr ExitProc, addr AppName, MB_OK+MB_ICONINFORMATION.break.elseif DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENTinvoke wsprintf, addr buffer, addr ProcessInfo, DBEvent.u.CreateProcessInfo.hFi le, DBEvent.u.CreateProcessInfo.hProcess, DBEvent.u.CreateProcessInfo.hThread, DBEvent.u.CreateProcessInfo.lpBaseOfImage, DBEvent.u.CreateProcessInfo.lpStartA ddressinvoke MessageBox,0, addr buffer, addr AppName, MB_OK+MB_ICONINFORMATION.elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT.if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINU E.continue.endif.elseif DBEvent.dwDebugEventCode==CREATE_THREAD_DEBUG_EVENTinvoke MessageBox,0, addr NewThread, addr AppName, MB_OK+MB_ICONINFORMATION.elseif DBEvent.dwDebugEventCode==EXIT_THREAD_DEBUG_EVENTinvoke MessageBox,0, addr EndThread, addr AppName, MB_OK+MB_ICONINFORMATION.endifinvoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_EXCEPTI ON_NOT_HANDLED.endwinvoke CloseHandle,pi.hProcessinvoke CloseHandle,pi.hThread.endifinvoke ExitProcess, 0end start分析:程序首先填充OPENFILENAME结构,调用GetOpenFileName让用户选择要调试的程序. invoke GetStartupInfo,addr startinfoinvoke CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, DEBUG_PROCESS+ DEBU G_ONLY_THIS_PROCESS, NULL, NULL, addr startinfo, addr pi当接收用户选择后,调用CreateProcess装载程序.并调用GetStartupInfo以默认值填充STARTUPINFO结构.注意我们将DEBUG_PROCESS标志与DEBUG_ONLY_THIS_PROCESS标志组合来仅调试这个程序,不包括子进程..while TRUEinvoke WaitForDebugEvent, addr DBEvent, INFINITE在debuggee被装入后,我们调用WaitForDebugEvent进入无尽的调试循环,WaitForDeb ugEvent在debuggee中发生调试事件时返回,因为我们指定了INFINITE作为第二个参数.当调试事件发生时, WaitForDebugEvent 返回并填充DBEvent结构.本文来自编程入门网---w .if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENTinvoke MessageBox, 0, addr ExitProc, addr AppName, MB_OK+MB_ICONINFORMATION.break我们要先检查dwDebugEventCode的值, 如果是EXIT_PROCESS_DEBUG_EVENT,用一个消息框显示"The debuggee exits" 并退出调试循环..elseif DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENTinvoke wsprintf, addr buffer, addr ProcessInfo, DBEvent.u.CreateProcessInfo.hFi le, DBEvent.u.CreateProcessInfo.hProcess, DBEvent.u.CreateProcessInfo.hThread, DBEvent.u.CreateProcessInfo.lpBaseOfImage, DBEvent.u.CreateProcessInfo.lpStartA ddressinvoke MessageBox,0, addr buffer, addr AppName, MB_OK+MB_ICONINFORMATION 如果dwDebugEventCode 的值为CREATE_PROCESS_DEBUG_EVENT,我们就在消息框中显示一些感兴趣的底层信息.这些信息从u.CreateProcessInfo获得. CreateProcessInfo是一个CREATE_PROCESS_DEBUG_INFO类型的结构体.你可以查阅Win32 API获得它的更多信息e..elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT.if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINU E.continue.endif如果dwDebugEventCode 的值为EXCEPTION_DEBUG_EVENT,我们就要更进一步检查异常类型.它是一大堆的结构嵌套,但我们可以从ExceptionCode成员获得异常类型.如果ExceptionCode的值为 EXCEPTION_BREAKPOINT并且是第一次发生(或者我们已知道deuggee中没有int 3h指令),我们可以安全地假定在debuggee要执行第一条指令时发生这一异常.在我们完成这些处理后,就可以用 DBG_CONTINUE调用ContinueDebugEvent来继续执行debuggee.接着我们继续等待下一个调试事件的发生..elseif DBEvent.dwDebugEventCode==CREATE_THREAD_DEBUG_EVENTinvoke MessageBox,0, addr NewThread, addr AppName, MB_OK+MB_ICONINFORMATION.elseif DBEvent.dwDebugEventCode==EXIT_THREAD_DEBUG_EVENTinvoke MessageBox,0, addr EndThread, addr AppName, MB_OK+MB_ICONINFORMATION.endif如果dwDebugEventCode 的值为CREATE_THREAD_DEBUG_EVENT或EXIT_THREAD_DEBUG_E VENT, 我们的程序显示一个消息框.invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_EXCEPTI ON_NOT_HANDLED.endw除了上面讨论过的 EXCEPTION_DEBUG_EVENT,用DBG_EXCEPTION_NOT_HANDLED标志调用ContinueDebugEvent函数恢复debuggee的执行.invoke CloseHandle,pi.hProcessinvoke CloseHandle,pi.hThread当debuggee结束时,我们就跳出了调试循环,这时要关闭 debuggee的线程和进程句柄.关闭这些句柄并不意味着要关闭这些进程和线程.只是说不再用这些句柄罢了.。

win32汇编除法

win32汇编除法

win32汇编除法1. 简介win32汇编是一种低级编程语言,用于在Windows操作系统上编写应用程序。

在win32汇编中,除法操作是非常常见的,它允许将两个数相除并得到商和余数。

本文将介绍win32汇编中的除法操作,包括如何使用除法指令、处理异常和处理特殊情况。

2. 除法指令win32汇编提供了两个除法指令:div和idiv。

•div指令用于无符号整数的除法操作。

它使用eax寄存器作为除数,并将商存储在eax中,余数存储在edx中。

•idiv指令用于有符号整数的除法操作。

它使用eax寄存器作为除数,并将商存储在eax中,余数存储在edx中。

以下是一个示例程序,展示如何在win32汇编中使用除法指令:mov eax, 10 ; 设置除数mov ebx, 3 ; 设置被除数div ebx ; 无符号整数除法; 此时 eax = 3(商),edx = 1(余数)idiv ebx ; 有符号整数除法; 此时 eax = -3(商),edx = 1(余数)3. 处理异常在进行除法操作时,可能会出现一些异常情况,例如被除数为0或除数与被除数的符号不同。

为了处理这些异常,win32汇编提供了一些标志位。

•CF(Carry Flag)标志位用于指示除法操作是否溢出。

如果除数为0,则CF会被设置为1。

•ZF(Zero Flag)标志位用于指示商是否为0。

如果商为0,则ZF会被设置为1。

以下是一个处理除法异常的示例程序:mov eax, 10 ; 设置除数mov ebx, 0 ; 设置被除数为0div ebx ; 无符号整数除法jnc success ; 如果没有溢出,跳转到成功处理的标签; 处理除法异常的代码; ...success:; 处理除法成功的代码; ...4. 处理特殊情况除法操作还涉及一些特殊情况的处理。

例如,当进行除法操作时,如果商的结果无法放入指定的寄存器,会导致溢出。

为了处理这种情况,可以使用cwd指令将32位有符号整数转换为64位有符号整数。

windows环境下32位汇编语言程序设计附书代码

windows环境下32位汇编语言程序设计附书代码

windows环境下32位汇编语言程序设计附书代码汇编语言是一种底层计算机语言,用于编写与计算机硬件直接交互的程序。

在Windows环境下,可以使用32位汇编语言进行程序设计。

本文将介绍一些常见的32位汇编语言程序,并附带相关的代码示例。

1.程序的基本结构:在32位汇编语言中,程序的基本结构由三个部分组成:数据段、代码段和堆栈段。

数据段用来声明和初始化程序中使用的全局变量和常量。

例如,下面的代码段声明了一个全局变量message,存储了一个字符串。

```data segmentmessage db 'Hello, World!',0data ends```代码段包含了程序的实际执行代码。

下面的代码段使用`mov`指令将message变量中的字符串存储到寄存器eax中,并使用`int 21h`来调用MS-DOS功能1来显示字符串。

```code segmentstart:mov eax, offset messagemov ah, 09hint 21hmov ah, 4chint 21hcode ends```堆栈段用来存储函数调用过程中的局部变量和返回地址。

2.入栈和出栈操作:在程序中,我们经常需要使用堆栈来保存和恢复寄存器的值,以及传递函数参数和保存函数返回值。

以下是一些常用的堆栈操作指令: ```push reg ;将reg中的值压入堆栈pop reg ;将堆栈顶部的值弹出到reg中```下面的示例演示了如何使用堆栈来保存和恢复寄存器的值:```code segmentstart:push eax ;将eax保存到堆栈mov eax, 10 ;设置eax的值为10pop ebx ;将堆栈顶部的值弹出到ebxadd eax, ebx ;将eax和ebx相加int 3 ;调试中断,用于程序的暂停mov ah, 4chint 21hcode ends```3.条件判断和跳转指令:汇编语言中的条件判断和跳转指令用于根据条件的成立与否来改变程序的执行流程。

Windows 环境下32 位汇编语言程序设计(罗云彬)_02

Windows 环境下32 位汇编语言程序设计(罗云彬)_02

选项 /c(常用) /coff(必用) /Cp(常用) /Fo filename /Fe filename
表 2.1 列出了不同版本 MASM 编译器的区别。
表 2.1 MASM 编译器各版本的区别
版本 MASM 4.00
MASM 5.00 MASM 5.10 MASM 5.10B MASM 6.00
MASM 6.00A MASM 6.00B MASM 6.10 MASM 6.10A MASM 6.11 MASM 6.11C MASM 6.12 MASM 6.13 MASM 6.14 MASM 6.15
/ddk/ddk98.asp
注意:整个 Win98ddk.exe 文件有 18 MB 之大!得到了 MASM 6.11d 之后,可以从 Microsoft 获取升级软件一直升级到最新的版本,升级包的下载地址是:
ftp:///softlib/mslfiles
不同版本 MASM 产生的 obj 文件的格式也不相同,在 DOS 和 Win16 时期,Microsoft 使 用的 obj 文件格式为 OMF 格式(Intel Object Module Format),到了 Win32 时期后改用了 COFF 格式(Common Object File Format),原因之一是 COFF 格式更像最终的 PE 文件,在链接的 时候可以做更少的处理,MASM 从 6.11 版本开始支持 COFF 格式。
资源文件中可以包括对话框、快捷键、菜单、字符串、版本信息和一些图形资源等内容。 资源文件的源文件是一种类似 脚本 的文本文件。其中用不同的语法定义了不同类型的资 源。资源脚本文件的扩展名一般为 rc,经过资源编译器编译成资源文件*.res。资源脚本文件 同样用到很多预定义值,所以软件包中一般也有资源头文件可供源文件来导入。MASM32 软 件包中的资源头文件是 Resource.h。

恶意程序是怎样写成的Win32汇编语言编写

恶意程序是怎样写成的Win32汇编语言编写

这些就是第一步所以设定的.在启动方式中,估计注册表Run启动是最脆弱的,复制到启动文件夹的话,又明显.最好的办法是创建远程线程,然后打开文件管理器explorer.exe插入,并且还能隐藏.有个例子是隐藏窗口进程的,桌面的窗口类是"Progman",我想插进去rundll32.exe,无奈不知道它的类,所以将就些,把目标定位注册表启动,况且这个我掌握的也比较熟悉.
.endif
ret
_WriteKey endp
做完后,这一步就到了传播,呵呵,不过偶没写,就来个"invokeDeleteFile,addrszDirectory"删除,然后也就退出了"invokeExitProcess,NULL"虽然说恶意程序,但是破坏的地方不多.如果要模拟"万花谷"的破坏方式,也就是禁止了注册表而已,这个完全可以做到.程序的完整代码如下:
szDword dd 1;数据
调用了子程序_WriteKey来完成:
Copycode
_WriteKey proc _lpKey
local @hKey,@dwIndex,@dwLastTime:FILETIME
invoke RegCreateKey,HKEY_CURRENT_USER,offsetszWriteKey,addr@hKey
_AttribCmdproc
invokeGetStartupInfo,addrstStartUp
invokeCreateProcess,NULL,addrszCmdAttrib,NULL,NULL,NULL,\
NORMAL_PRIORITY_CLASS,NULL,NULL,addrstStartUp,addrstProcInfo

32位汇编指令

32位汇编指令

用OD和CE,总不断找汇编资料,解读指令,实在是累。

总算找到篇比较完整的资料,与大家分享。

32位CPU所含有的寄存器有:4个数据寄存器(EAX、EBX、ECX和EDX)2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP)6个段寄存器(ES、CS、SS、DS、FS和GS)1个指令指针寄存器(EIP) 1个标志寄存器(EFlags)1、数据寄存器数据寄存器主要用来保存操作数和运算结果等信息,从而节省读取操作数所需占用总线和访问存储器的时间。

32位CPU有4个32位的通用寄存器EAX、EBX、ECX和EDX。

对低16位数据的存取,不会影响高16位的数据。

这些低16位寄存器分别命名为:AX、BX、CX和DX,它和先前的CPU中的寄存器相一致。

4个16位寄存器又可分割成8个独立的8位寄存器(AX:AH-AL、BX:BH-BL、CX:CH-CL、DX:DH-DL),每个寄存器都有自己的名称,可独立存取。

程序员可利用数据寄存器的这种“可分可合”的特性,灵活地处理字/字节的信息。

寄存器EAX通常称为累加器(Accumulator),用累加器进行的操作可能需要更少时间。

可用于乘、除、输入/输出等操作,使用频率很高;寄存器EBX称为基地址寄存器(Base Register)。

它可作为存储器指针来使用;寄存器ECX称为计数寄存器(Count Register)。

在循环和字符串操作时,要用它来控制循环次数;在位操作中,当移多位时,要用CL来指明移位的位数;寄存器EDX称为数据寄存器(Data Register)。

在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址。

在16位CPU中,AX、BX、CX和DX不能作为基址和变址寄存器来存放存储单元的地址,在32位CPU中,其32位寄存器EAX、EBX、ECX和EDX不仅可传送数据、暂存数据保存算术逻辑运算结果,而且也可作为指针寄存器,所以,这些32位寄存器更具有通用性。

汇编语言第六章

汇编语言第六章

三.中断向量表
3. 设置或取出中断向量指令 (1) 设置中断向量指令 功能:把由AL指定的中断类型的中断向量DS:DX放入中
断向量表中。
(AH)= 25H
(AL)= 中断类型号
DS:DX = 中断向量 INT 21H
三.中断向量表
(2) 取出中断向量指令
功能:把AL中指定的中断类型的中断向量从中断
一、 WIN32编程基础
(2) 循环控制伪指令
格式:.WHILE 条件表达式 循环体 .ENDW 格式:.REPEAT 循环体 .UNTIL 条件表达式 格式:.CONTINUE 功能:终止本次循环, 开始下一次循环 格式:.BREAK 功能:退出当前循环
功能:实现循环结构
一、 WIN32编程基础
内中断的处理特点: ①中断类型号一般在指令中; ② 不受中断允许标志位IF的影响。
二、 中断源
2. 外中断 由外设控制器、协处理器等CPU以外的事件引起的中断, 称为外中断。 外中断的处理特点: ① 中断类型号由8259A提供,或由自制电路来提供;
② 受中断允许标志位IF的影响(IF=1,响应中断)。
个字节。
三.中断向量表
如:INT 4AH
中断向量地址 = 4AH*4 = 128H
DEBUG执行后, 用D命令查看: ―D0:0↙ … 执行INT 4AH时: IP=1805H CS=F000H IP F000: 1805 中断处理
0:128H
0:129H
05 18
0:12AH
0:12BH
00
F0 …
外设
二、 外设与主机传送的接口与信息
接口的组成:设备状态寄存器、设备控制寄存 器、数据寄存器。 I/O端口的地址空间:允许设置64K个8位端口 或32K个16位端口。 如:40H~43H时钟/定时器,60H~63H为 8255通讯芯片的接口。

罗云彬的Win32汇编教程

罗云彬的Win32汇编教程

罗云彬的Win32汇编教程之一Win32汇编的环境和基础1.32位环境简介在Dos下编汇编程序,我们可以管理系统的所有资源,我们可以改动系统中所有的内存,如自己改动内存控制块来分配内存,自己修改中断向量表来截获中断等,对其他操作也是如此,如我们对键盘端口直接操作就可以把键盘屏蔽掉,可以这样来描述Dos系统:系统只有一个特权级别,在编程上讲,任何程序和操作系统都是同级的,所以在Dos下,一个编得不好的程序会影响其他所有的程序,如一个程序把键盘口中断关掉了,所有程序就都不能从键盘获得键入的数据,直到任何一个程序重新打开键盘为止,一个程序陷入死循环,也没有其他程序可以把它终止掉。

Dos下的编程思路是“单任务”的,你只要认为你的程序会按照你的流程一步步的执行下去,不必考虑先后问题(当然程序可能会被中断打断,但你可以认为它们会把环境恢复,如果中断程序没有把环境恢复,那是他们的错)。

在内存管理方式上,Dos汇编和Win32汇编也有很多的不同:Dos工作在实模式下,我们可以寻址1M 的内存,寻址时通过段寄存器来制定段的初始地址,每个段的大小为64K,超过1M的部分,就只能把他作为XMS使用,也就是说,只能用作数据存放使用而无法在其中执行程序。

而Windows在保护模式下执行,这里所有的资源对应用程序来说都是被“保护”的:程序在执行中有级别之分,只有操作系统工作在最高级--0级中,所有应用程序都工作在3级中(Ring3),在Ring3中,你无法直接访问IO端口,无法访问其他程序运行的内存,连向程序自己的代码段写入数据都是非法的,会在Windows的屏幕上冒出一个熟悉的蓝屏幕来。

只有对Ring0的程序来说,系统才是全开放的。

在内存方面,Windows使用了处理器的分页机制,使得对应用程序来说,所有的内存都是“平坦”的,你不必用一个段寄存器去指定段的地址,因为在保护模式下,段寄存器的含义是不同的(可以参见80386手册方面的书籍),你可以直接指定一个32位的地址来寻址4GB的内存。

Win32汇编语言简明教程

Win32汇编语言简明教程

第一课基本概念我们先假设您已知道了如何使用MASM。

如果您还不知道的话,请下载win32asm.exe ,并请仔细研读其中所附带的文档资料。

好,如果您已准备就绪,我们这就开始吧!理论:WIN32 程序运行在保护模式下的,保护模式的历史可以追溯到 80286。

而今80286 已成为了历史。

所以我们将只把精力集中于 80386 及后续的X86 系列CPU。

Windows 把每一个 Win32 应用程序放到分开的虚拟地址空间中去运行,也就是说每一个应用程序都拥有其相互独立的 4GB 地址空间,当然这倒不是说它们都拥有 4GB 的物理地址空间,而只是说能够在 4GB 的范围内寻址。

操作系统将会在应用程序运行时完成 4GB 的虚拟地址和物理内存地址间的转换。

这就要求编写应用程序时必须格守 Windows 的规范,否则极易引起内存的保护模式错误。

而过去的 Win16 内存模式下,所有的应用程序都运行于同一个 4GB 地址空间,它们可以彼此"看"到别的程序的内容,这极易导致一个应用程序破坏另一个应用程序甚至是操作系统的数据或代码。

和 16 位 Windows 下的把代码分成 DATA,CODE 等段的内存模式不同,WIN32 只有一种内存模式,即 FLAT 模式,意思是"平坦"的内存模式,再没有 64K 的段大小限制,所有的 WIN32 的应用程序运行在一个连续、平坦、巨大的 4GB 的空间中。

这同时也意味着您无须和段寄存器打交道,您可以用任意的段寄存器寻址任意的地址空间,这对于程序员来说是非常方便的,这也使得用32位汇编语言和用C语言一样方便。

在Win32下编程,有许多重要的规则需要遵守。

有一条很重要的是:Windows 在内部频繁使用 ESI,EDI,EBP,EBX 寄存器,而且并不去检测这些寄存器的值是否被更改,这样当您要使用这些寄存器时必须先保存它们的值,待用完后再恢复它们,一个最显著的应用例子就是 Windows 的CallBack 函数中。

Iczelion的Win32汇编教程008

Iczelion的Win32汇编教程008
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
MenuName db "FirstMenu",0 ; The name of our menu in the resource file.
MyMenu MENU
{
[menu list here]
}
这和C语言中的结构体的定义非常相似。 MyMenu类似于被定义的变量,而MENU则类似于关键字。当然您可以用另外一种办法,那就是用BEGIN和END来代替花括号,这和PASCAL语言中的风格相同。
在菜单项的列表中是一大串的MENUITEM和POPUP语句。MENUITEM定义了一个菜单项,当选择后不会激活对话框。它的语法如下:
mov hMenu, eax
invoke CreateWindowEx,NULL,OFFSET ClsName,\
OFFSET Caption, WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT,CW_USEDEFAULT,\
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc

Win32汇编-字符串浮点数运算过程

Win32汇编-字符串浮点数运算过程

Win32汇编-字符串浮点数运算过程整理复习汇编语⾔的知识点,以前在学习《Intel汇编语⾔程序设计 - 第五版》时没有很认真的整理笔记,主要因为当时是以学习理解为⽬的没有整理的很详细,这次是我第三次阅读此书,每⼀次阅读都会有新的收获,这次复习,我想把书中的重点,再⼀次做⼀个归纳与总结(注:16位汇编部分跳过),并且继续尝试写⼀些有趣的案例,这些案例中所涉及的指令都是逆向中的重点,⼀些不重要的我就直接省略了,⼀来提⾼⾃⼰,⼆来分享知识,转载请加出处,敲代码备注挺难受的。

该笔记重点复习字符串操作指令的⼀些使⽤技巧,以及浮点数运算相关内容,浮点数运算也是⾮常重要的知识点,在分析⼤型游戏时经常会碰到针对浮点数的运算指令,例如枪械换弹动作,⼈物跳跃时的状态,都属于浮点数运算范围,也就⼀定会⽤到浮点数寄存器栈,浮点指令集主要可分为,传送指令,算数指令,⽐较指令,超越指令,常量加载指令等。

再次强调:该笔记主要学习的是汇编语⾔,不是研究编译特性的,不会涉及到编译器的优化与代码还原。

字符串操作指令移动串指令: MOVSB、MOVSW、MOVSD ;从 ESI -> EDI; 执⾏后, ESI 与 EDI 的地址移动相应的单位⽐较串指令: CMPSB、CMPSW、CMPSD ;⽐较 ESI、EDI; 执⾏后, ESI 与 EDI 的地址移动相应的单位扫描串指令: SCASB、SCASW、SCASD ;依据 AL/AX/EAX 中的数据扫描 EDI 指向的数据, 执⾏后 EDI ⾃动变化储存串指令: STOSB、STOSW、STOSD ;将 AL/AX/EAX 中的数据储存到 EDI 给出的地址, 执⾏后 EDI ⾃动变化载⼊串指令: LODSB、LODSW、LODSD ;将 ESI 指向的数据载⼊到 AL/AX/EAX, 执⾏后 ESI ⾃动变化移动串指令: 移动串指令包括MOVSB、MOVSW、MOVSD原理为从ESI到EDI中,执⾏后将ESI地址⾥⾯的内容移动到EDI指向的内存空间中,该指令常⽤于对特定字符串的复制操作..386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude msvcrt.incincludelib msvcrt.lib.data; 逐字节拷贝SrcString BYTE "hello lyshark",0h ; 源字符串SrcStringLen EQU $ - SrcString - 1 ; 计算出原始字符串长度DstString BYTE SrcStringLen dup(?),0h ; ⽬标内存地址szFmt BYTE '字符串: %s 长度: %d ',0dh,0ah,0; 四字节拷贝ddSource DWORD 10h,20h,30h ; 定义三个四字节数据ddDest DWORD lengthof ddSource dup(?) ; 得到⽬标地址.codemain PROC; 第⼀种情况: 实现逐字节拷贝cld ; 清除⽅向标志mov esi,offset SrcString ; 取源字符串内存地址mov edi,offset DstString ; 取⽬标字符串内存地址mov ecx,SrcStringLen ; 指定循环次数,为原字符串长度rep movsb ; 逐字节复制,直到ecx=0为⽌lea eax,dword ptr ds:[DstString]mov ebx,sizeof DstStringinvoke crt_printf,addr szFmt,eax,ebx; 第⼆种情况: 实现4字节拷贝lea esi,dword ptr ds:[ddSource]lea edi,dword ptr ds:[ddDest]cldrep movsd; 使⽤loop循环逐字节复制lea esi,dword ptr ds:[SrcString]lea edi,dword ptr ds:[DstString]mov ecx,SrcStringLencld ; 设置⽅向为正向复制@@: movsb ; 每次复制⼀个字节dec ecx ; 循环递减jnz @B ; 如果ecx不为0则循环lea eax,dword ptr ds:[DstString]mov ebx,sizeof DstStringinvoke crt_printf,addr szFmt,eax,ebxinvoke ExitProcess,0main ENDPEND main⽐较串指令: ⽐较串指令包括CMPSB、CMPSW、CMPSD⽐较ESI、EDI执⾏后将ESI指向的内存操作数同EDI指向的内存操作数相⽐较,其主要从ESI 指向内容减去EDI的内容来影响标志位..386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude msvcrt.incincludelib msvcrt.lib.data; 逐字节⽐较SrcString BYTE "hello lyshark",0hDstStringA BYTE "hello world",0h.constszFmt BYTE '字符串: %s',0dh,0ah,0YES BYTE "相等",0NO BYTE "不相等",0.codemain PROC; 实现字符串对⽐,相等/不相等输出lea esi,dword ptr ds:[SrcString]lea edi,dword ptr ds:[DstStringA]mov ecx,lengthof SrcStringcldrepe cmpsbje L1jmp L2L1: lea eax,YESinvoke crt_printf,addr szFmt,eaxjmp lop_endL2: lea eax,NOinvoke crt_printf,addr szFmt,eaxjmp lop_endlop_end:int 3invoke ExitProcess,0main ENDPEND mainCMPSW 是对⽐⼀个字类型的数组,只有当数组中的数据完全⼀致的情况下才会返回真,否则为假..386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude msvcrt.incincludelib msvcrt.lib.dataArray1 WORD 1,2,3,4,5 ; 必须全部相等才会清空ebxArray2 WORD 1,3,5,7,9.constszFmt BYTE '数组: %s',0dh,0ah,0YES BYTE "相等",0NO BYTE "不相等",0.codemain PROClea esi,Array1lea edi,Array2mov ecx,lengthof Array1cldrepe cmpswje L1lea eax,NOinvoke crt_printf,addr szFmt,eaxjmp lop_endL1: lea eax,YESinvoke crt_printf,addr szFmt,eaxjmp lop_endlop_end:int 3invoke ExitProcess,0main ENDPEND mainCMPSD则是⽐较双字数据,同样可⽤于⽐较数组,这⾥就演⽰⼀下⽐较单数的情况..386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude msvcrt.incincludelib msvcrt.lib.datavar1 DWORD 1234hvar2 DWORD 5678h.constszFmt BYTE '两者: %s',0dh,0ah,0YES BYTE "相等",0NO BYTE "不相等",0.codemain PROClea esi,dword ptr ds:[var1]lea edi,dword ptr ds:[var2]cmpsdje L1lea eax,dword ptr ds:[YES]invoke crt_printf,addr szFmt,eaxjmp lop_endL1: lea eax,dword ptr ds:[NO]invoke crt_printf,addr szFmt,eaxjmp lop_endlop_end:int 3invoke ExitProcess,0main ENDPEND main扫描串指令: 扫描串指令包括SCASB、SCASW、SCASD其作⽤是把AL/AX/EAX中的值同EDI寻址的⽬标内存中的数据相⽐较,这些指令在⼀个长字符串或者数组中查找⼀个值的时候特别有⽤..386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude msvcrt.incincludelib msvcrt.lib.dataszText BYTE "ABCDEFGHIJK",0.constszFmt BYTE '字符F所在位置: %d',0dh,0ah,0.codemain PROC; 寻找单⼀字符找到会返回第⼏个字符lea edi,dword ptr ds:[szText]mov al,"F"mov ecx,lengthof szText -1cldrepne scasb ; 如果不相等则重复扫描je L1xor eax,eax ; 如果没找到F则清空eaxjmp lop_endL1: sub ecx,lengthof szText -1neg ecx ; 如果找到输出第⼏个字符invoke crt_printf,addr szFmt,ecxlop_end:int 3main ENDPEND main如果我们想要对数组中某个值是否存在做判断可以使⽤SCASD指令,对数组进⾏扫描..386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude msvcrt.incincludelib msvcrt.lib.dataMyArray DWORD 65,88,93,45,67,89,34,67,89,22.constszFmt BYTE '数值: %d 存在',0dh,0ah,0.codemain PROClea edi,dword ptr ds:[MyArray]mov eax,34mov ecx,lengthof MyArray - 1cldrepne scasdje L1xor eax,eaxjmp lop_endL1: sub ecx,lengthof MyArray - 1neg ecxinvoke crt_printf,addr szFmt,ecx,eaxlop_end:int 3main ENDPEND main储存串指令: 存储指令主要包括STOSB、STOSW、STOSD起作⽤是把AL/AX/EAX中的数据储存到EDI给出的地址中,执⾏后EDI的值根据⽅向标志的增加或减少,该指令常⽤于初始化内存或堆栈..386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude msvcrt.incincludelib msvcrt.lib.dataCount DWORD 100String BYTE 100 DUP(?),0.codemain PROC; 利⽤该指令初始化字符串mov al,0ffh ; 初始化填充数据lea di,byte ptr ds:[String] ; 待初始化地址mov ecx,Count ; 初始化字节数cld ; 初始化:⽅向=前⽅rep stosb ; 循环填充; 存储字符串: 使⽤A填充内存lea edi,dword ptr ds:[String]mov al,"A"mov ecx,Countcldrep stosbint 3main ENDPEND main载⼊串指令: 载⼊指令主要包括LODSB、LODSW、LODSD起作⽤是将ESI指向的内存位置向AL/AX/EAX中装载⼀个值,同时ESI的值根据⽅向标志值增加或减少,如下分别完成加法与乘法计算,并回写到内存中..386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude msvcrt.incincludelib msvcrt.lib.dataArrayW WORD 1,2,3,4,5,6,7,8,9,10ArrayDW DWORD 1,2,3,4,5ArrayMulti DWORD 10szFmt BYTE '计算结果: %d ',0dh,0ah,0.codemain PROC; 利⽤载⼊命令计算数组加法lea esi,dword ptr ds:[ArrayW]mov ecx,lengthof ArrayWxor edx,edxxor eax,eax@@: lodsw ; 将输⼊加载到EAXadd edx,eaxloop @Bmov eax,edx ; 最后将相加结果放⼊eaxinvoke crt_printf,addr szFmt,eax; 利⽤载⼊命令(LODSD)与存储命令(STOSD)完成乘法运算mov esi,offset ArrayDW ; 源指针mov edi,esi ; ⽬的指针cld ; ⽅向=向前mov ecx,lengthof ArrayDW ; 循环计数器L1: lodsd ; 加载[esi]⾄EAXmul ArrayMulti ; 将EAX乘以10stosd ; 将结果从EAX存储⾄[EDI]loop L1; 循环读取数据(存在问题)mov esi,offset ArrayDW ; 获取基地址mov ecx,lengthof ArrayDW ; 获取长度xor eax,eax@@: lodsdinvoke crt_printf,addr szFmt,eaxdec ecxloop @Bint 3main ENDPEND main统计字符串: 过程StrLength()通过循环⽅式判断字符串结尾的0标志,来统计字符串的长度,最后将结果存储在EAX中..386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude msvcrt.incincludelib msvcrt.lib.dataString BYTE "hello lyshark",0szFmt BYTE '计算结果: %d ',0dh,0ah,0.code; 计算字符串长度StrLength PROC USES edi,pString:PTR BYTEmov edi,offset String ; 取出字符串的基地址xor eax,eax ; 清空eax⽤作计数器L1: cmp byte ptr [edi],0 ; 分别那[edi]的值和0作⽐较je L2 ; 上⼀步为零则跳转得到retinc edi ; 否则继续执⾏inc eaxjmp L1L2: retStrLength endpmain PROCinvoke StrLength, addr Stringinvoke crt_printf,addr szFmt,eaxint 3main ENDPEND main字符串转换: 字符串转换是将⼩写转为⼤写,或者将⼤写转为⼩写,其原理是将⼆进制位第五位置1或0则可实现. .386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude msvcrt.incincludelib msvcrt.lib.dataMyString BYTE "hello lyshark",0szFmt BYTE '结果: %s ',0dh,0ah,0.codemain PROCmov esi,offset MyString ; 取出字符串的偏移地址L1: cmp byte ptr [esi],0 ; 分别拿出每⼀个字节,与0⽐较je L2 ; 如果相等则跳转到L2and byte ptr [esi],11011111b ; 执⾏按位与操作inc esi ; 每次esi指针递增1jmp L1 ; 重复循环L2: lea eax,dword ptr ds:[MyString]invoke crt_printf,addr szFmt,eaxretmain ENDPEND main字符串拷贝: 使⽤两个指针分别指向两处区域,然后通过变址寻址的⽅式实现对特定字符串的拷贝..386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude msvcrt.incincludelib msvcrt.lib.datasource BYTE "hello lyshark welcome",0htarget BYTE SIZEOF source DUP(0),0h ; 取源地址数据⼤⼩szFmt BYTE '结果: %s ',0dh,0ah,0.codemain PROC; 实现正向拷贝字符串mov esi,0 ; 使⽤变址寄存器mov ecx,sizeof source ; 循环计数器L1:mov al,byte ptr ds:[source + esi] ; 从源地址中取⼀个字符mov byte ptr ds:[target + esi],al ; 将该字符存储在⽬标地址中inc esi ; 递增,将指针移动到下⼀个字符loop L1lea eax,dword ptr ds:[target]invoke crt_printf,addr szFmt,eax; 实现反向拷贝字符串mov esi,sizeof sourcemov ecx,sizeof sourcemov ebx,0L2:mov al,byte ptr ds:[source + esi]mov byte ptr ds:[target + esi],aldec esiinc ebxloop L2lea eax,dword ptr ds:[target]invoke crt_printf,addr szFmt,eaxpush 0call ExitProcessmain ENDPEND main浮点数操作指令集(重点)浮点数的计算是不依赖于CPU的,运算单元是从80486处理器开始才被集成到CPU中的,该运算单元被称为FPU浮点运算模块,FPU不使⽤CPU 中的通⽤寄存器,其有⾃⼰的⼀套寄存器,被称为浮点数寄存器栈,FPU将浮点数从内存中加载到寄存器栈中,完成计算后在回写到内存中.FPU有8个可独⽴寻址的80位寄存器,分别名为R0-R7他们以堆栈的形式组织在⼀起,栈顶由FPU状态字中的⼀个名为TOP的域组成,对寄存器的引⽤都是相对于栈顶⽽⾔的,栈顶通常也被叫做ST(0),最后⼀个栈底则被记作ST(7)其实⽤⽅式与堆栈完全⼀致.浮点数运算通常会使⽤⼀些更长的数据类型,如下就是MASM汇编器定义的常⽤数据类型..datavar1 QWORD 10.1 ; 64位整数var2 TBYTE 10.1 ; 80位(10字节)整数var3 REAL4 10.2 ; 32位(4字节)短实数var4 REAL8 10.8 ; 64位(8字节)长实数var5 REAL10 10.10 ; 80位(10字节)扩展实数此外浮点数对于指令的命名规范也遵循⼀定的格式,浮点数指令总是以F开头,⽽指令的第⼆个字母则表⽰操作位数,例如:B表⽰⼆⼗进制操作数,I 表⽰⼆进制整数操作,如果没有指定则默认则是针对实数的操作fld等.FLD/FSTP 操作指令: 这两个指令是最基本的浮点操作指令,其中的FLD⼊栈指令,后⾯的FSTP则是将浮点数弹出堆栈..386p.model flat,stdcalloption casemap:noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude msvcrt.incincludelib msvcrt.lib.datavar1 QWORD 10.0var2 QWORD 20.0var3 QWORD 30.0var4 QWORD 40.0result QWORD ?.codemain PROC; 初始化浮点单元finit; 依次将数据⼊栈fld qword ptr ds:[var1]fld qword ptr ds:[var2]fld qword ptr ds:[var3]fld qword ptr ds:[var4]; 获取当前ST(0)栈帧元素fst qword ptr ds:[result]; 从栈中弹出元素fstp qword ptr ds:[result]fstp qword ptr ds:[result]fstp qword ptr ds:[result]fstp qword ptr ds:[result]int 3main ENDPEND main压栈时会⾃动向下填充,⽽出栈时则相反,不但要出栈,还会将地址回绕到底部,覆盖掉底部的数据。

Win32汇编语言程序设计.

Win32汇编语言程序设计.

; here begins our .const section .const NULL equ 0 MB_OK equ 0 ; here we start with our code
.code
Start: INVOKE INVOKE end Start
MessageBoxA, NULL, ADDR Text, ADDR Caption, MB_OK ExitProcess, NULL
函数调用后的返回值保存在EAX寄存器中
• sageBoxW ANSI(8位) Windows 9x
Unicode(16位) Windows NT
Win32 API的调用
•示例
; set options for the assembler .386 .model flat, stdcall ; declaration of all used API-functions ExitProcess MessageBoxA PROTO PROTO :DWORD :DWORD, :DWORD, :DWORD, :DWORD
Win32汇编语言程序的结构
• STDCALL调用规则
从右向左传递参数,被调函数负责对堆栈进行平衡
• 变长参数问题
int wsprintf( LPTSTR lpOut, LPCTSTR lpFmt, ...) 必须采用cdecl调用规则
二、Win32 API的调用
• Win32 API
API=Application Programming Interface 应用程序编程接口 Win32 API相当于DOS系统功能 kernel32.dll 包含处理内存和进程管理的API函数 user32.dll 主要用来控制用户界面 gdi32.dll 主要负责图形操作

【汇编语言】32位指令及其编程(可编辑)

【汇编语言】32位指令及其编程(可编辑)

封面第六章 32位指令及其编程第六章32位指令及其编程概述 6.1 32位指令运行环境6.2 32位扩展指令 6.3 32位指令的程序设计 6.4 32位新增指令 6.5 用汇编语言编写 32位WINDOWS应用程序概述1 概述 32位指令系统以80386 CPU 为基础,其指令集可分为整数指令集(16位整数指令集、32位整数指令集)和浮点指令集,16位整数指令集全兼容8086 CPU。

1996年,Intel推出MMX Pentium,首次增加了MMX (多媒体扩展)指令集,提高了CPU对多媒体数据的处理能力。

1999年,Intel推出Pentium Ⅲ,增加了SSE指令集(数据流SIMD扩展指令,SIMD为MMX指令集的关键技术,意为“单指令流多数据流”)。

2000年,Intel推出Pentium4,又增加SSE2指令集,增强了处理器对3-D图象、视频编码解码、语音识别等数据的处理能力。

概述2 本章主要介绍80386的32位整数指令集,及其汇编语言程序设计,对386以后推出的CPU新增指令(0>.、 .、.)简单介绍。

6.5 节简单介绍如何使用汇编语言编写WINDOWS应用程序。

本章应重点掌握: 32位编程环境 32位寻址方式 32位指令编程方法 6.1 32位指令运行环境 6.1 32位指令运行环境补充.386的工作方式及16位段和32位段 . 寄存器组 . 寻址方式 .机器代码格式 386的工作方式:实方式补充 386的工作方式实地址方式:实方式(Real Mode)与8086/80186的工作方式以及80286的实地址方式具有相同的基本结构。

不使用386的优先级分级制,所有程序(DOS和应用程序都工作在0级(特权级)。

32位x86 CPU只能寻址1MB物理存储器空间,分段最大64KB,采用16位逻辑段。

32位x86 CPU可以使用32位寄存器和32位操作数,也可以采用32位寻址方式。

Win10系统VS2022开发环境中(X86)Win32汇编(MASM32)环境配置和一些。。。

Win10系统VS2022开发环境中(X86)Win32汇编(MASM32)环境配置和一些。。。

Win10系统VS2022开发环境中(X86)Win32汇编(MASM32)环境配置和⼀些。

抱歉,还是只能⽤⽶国的软件以及技术以及等等等等。

如果配置完成,在vs2022调试环境下正确编译运⾏后,可以看到如下画⾯:在VS022中开发学习汇编必然很⽅便。

这⾥可以下载vs2022项⽬源码:注意, AsmDude()只⽀持到vs2019。

主要配置过程如下:step1: 按照vs2022(直接官⽹下载Community版本)step2:这⾥下载masm32v11r.zip这个压缩包step3: 将MASM32的install.exe运⾏安装到C盘(也可以是别的盘),安装过程注意同意其解压,这⾥会耽搁⼀⼩段时间。

step4: 在vs中建⽴⼀个控制台应⽤。

删除原来默认⽣成的cpp⽂件。

step5: 在项⽬图标上上右键, ⽣成依赖项->⽣成⾃定义->选中masm, 如下图:step6: 在源⽂件图标上右键,添加 -> 新建项, 新建 test.asm⽂件。

step7: 在test.asm写⼊代码如下:.386.model flat, stdcall.stack 4096option casemap:noneinclude windows.incinclude user32.incincludelib user32.libinclude kernel32.incincludelib kernel32.lib.constszCaption db '恭喜',0szText db 'Win32汇编程序成功编译!',0.dataExitProcess proto, dwExitcode: dword; 代码段.codemainT PROCinvoke MessageBox,NULL,offset szText,offset szCaption,MB_OKinvoke ExitProcess,NULLmainT ENDPEND mainT// 部分代码源⾃ <<[琢⽯成器—Windows环境下32位汇编语⾔程序设计].罗云彬.第三版>>上⾯代码中的 mainT是我这⾥为了解释如何配置⽽故意起的名字。

Win32编程

Win32编程

Win32编程此资料为ITjob软件开发教程网提供,特此分享,互相学习!C/C++/VC/MFC技术交流群:95453496一、Win32编程基本概念1、消息驱动在介绍Windows消息驱动概念之前,我们首先来回顾面向过程的程序结构:main()程序有明显的开始、中间过程和结束点,程序是围绕这个过程编写好相关的子过程,再把这些子过程串联在一起。

程序编好以后,该过程也就确定了,程序必须按照规定好的顺序执行:是否需要用户的输入、输入什么、程序取得用户输入以后做什么处理,处理完毕将结果显示给用户。

该过程一旦确定,程序的执行过程也是固定的,用户不能干预。

而Windows编程所采用设计思想是:消息驱动,又叫做事件驱动。

在这种程序结构中,程序没有明显的开始、结束,程序流程的控制由各种随机发生、不确定、没有预先设定顺序的事件的发生来触发。

是一个不断产生消息和处理消息的过程。

也就是说程序一运行开始处于等待消息状态,取得消息以后,就对该消息做出相应的处理,完成处理以后又进入等待消息的状态。

这种程序结构与Windows操作系统结合非常紧密,最明显一点就是消息的管理是由操作系统完成的。

应用程序从操作系统获得消息有两种方式:一种就是应用程序调用Windows提供的消息获取函数;另外一种就是回调函数,由操作系统自己调用。

这种消息驱动机制,有点像银行的柜台业务:早上八点,银行开门(Windows应用程序开始运行),每个营业员(Windwows线程)回到自己的柜台开始办公。

如果有顾客来办理相关业务(相当于Windows消息),那么对应的业务员就进行处理。

顾客来办理业务的时间以及业务类型都是随机的,如果某一时刻没有顾客办理业务并且没有到下班时间(Windows 应用程序退出)的话,那么相关的业务员进入等待状态。

所有的业务员不断重复该过程,直到下班(Windows应用程序退出)。

2、应用程序、操作系统、IO设备之间的相互关系3、窗口元素窗口:是Windows操作系统最重要最基本的一个概念。

Win32汇编--使用MASM

Win32汇编--使用MASM

Win32汇编--使⽤MASM经过上⼀讲的准备⼯作,相信⼤家已经搭建好了 Win32 汇编的⼯作环境,并已经知道编译、链接⼀个程序的过程和原理了。

现在,我们让例⼦回归到经典:include <stdio.h>int main(void){Printf(“Hello, world\n”);} // 事实上想想,这不正是初⽣的婴⼉?!⿇雀虽⼩,五脏俱全。

刚刚那个C语⾔的”Hello, world”程序包含了C语⾔中的最基本的格式。

在C语⾔的源程序中,我们不需要为堆栈段、数据段和代码段的定义⽽烦恼,编译器会⾃⼰解决。

回顾⼀下,在DOS 下的汇编这段代码会变成什么样? Follow me!;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 堆栈段;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>stack segmentdb 100 dup (?) ;定义100个字节的内存存储单元空间,默认值为?stack ends ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 数据段;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>data segmentszHello db ‘Hello, world’,0dh,0ah,’$’data ends ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 代码段;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>code segmentassume cs:code,ds:data,ss:stackstart:mov ax,datamov ds,axmov ah,9mov dx,offset szHelloint 21hmov ah,4chint 21hcode endsend start在例⼦中我们看到,stack、data、code都找到了⾃⼰的⼩窝。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Win32汇编语言教程作者:TBsoft一、引言Win32应用程序一般使用C语言编程,但是在某些需要进行深层编程的情况下,例如Win32应用程序执行机制分析、病毒清除、加密解密等深层编程,或者对于某些速度要求较高的程序,需要使用汇编语言(甚至机器语言)直接编写Win32应用程序。

Win32应用程序虽然和其他32位应用程序(例如32位保护模式DOS 程序)一样可以使用386汇编语言和保护模式编程,但是Win32应用程序的执行机制与其他32位应用程序有一定的差别,例如消息循环、动态链接等,Win32汇编语言也有其特殊的编程方式。

目前国内极少看到有关Win32汇编语言的资料,市面上的汇编语言书籍一般只介绍DOS实模式汇编语言和386保护模式汇编语言,金山公司的《深入Windows编程》一书虽然介绍了使用汇编语言写Windows应用程序的方法,可惜该书只介绍了 Win16汇编语言。

为了使大家能对Win32汇编语言的基本编程方法有一定的了解,近日得闲,笔者编写了本教程,旨在抛砖引玉,如果本教程能够带领你走进神秘的Win32汇编语言世界,笔者心愿足矣。

使用本教程,要求读者具有C语言编写Win32应用程序(Win32SDK 编程)的基础。

二、进行Win32汇编语言编程的基本软件进行Win32汇编语言编程,应该准备下列基本软件:1、MASM 6.11以上版本的汇编器MASM是Microsoft公司的汇编器,这是最基本的软件,必需MASM 6.11以上版本才能够汇编Win32汇编语言源程序。

不过进行Win32汇编语言编程不必要全套的MASM 6.11,只要一个ML.EXE文件就可以了,Windows 95 DDK中带有MASM 6.11c 的ML.EXE文件,Windows 98 DDK中带有MASM 6.11d的ML.EXE文件,都可以使用。

Turbo MASM 5.0(TASM)是Borland公司的汇编器,也可以用来汇编Win32汇编语言源程序,但是TASM的部分语法与MASM不同,用于MASM的 Win32汇编语言源程序可能需要修改后才能用TASM汇编。

本教程中的所有Win32汇编语言源程序都基于MASM。

2、Win32SDK进行Win32汇编语言编程需要用到Win32SDK中的资源编译器(RC.EXE)和连接器(LINK.EXE),还需要用到Win32SDK中的引入库文件(KERNEL32.LIB、USER32.LIB、GDI32.LIB等)。

如果没有Win32SDK,Platform SDK也可以,还可以安装Visual C++ 2.0以上版本的Visual C++,笔者使用的是Visual C++ 6.0。

Borland C++ 4.0以上版本的Borland C++也可以使用,只是资源编译器和连接器的文件名不同,分别是BRC.EXE(BRC32.EXE)和TLINK.EXE(TLINK32.EXE),选项也不尽相同,另外Borland C++不支持COFF格式的OBJ文件,汇编时不能使用/coff选项。

3、汇编语言编辑器一个普通的文本编辑器,用于编辑Win32汇编语言源程序。

EDIT、PWB等都可以,Visual C++等编程语言中的编辑器也可以,甚至WORD、WPS 97等可以编辑文本文件的字处理软件都可以,不过笔者推荐使用ASMEDIT,这是一个专用的汇编语言编辑器,效果非常好。

Win32汇编语言一般使用命令行方式汇编连接,经过一定的设置也可以在某些集成环境(PWB、Visual C++、ASMEDIT等)下汇编连接,还可以使用NMAKE工具,不过本教程中只使用命令行方式汇编连接,也不使用NMAKE工具。

三、ANSI字符集API与UNICODE字符集APIWin32 API中凡是与字符有关的API都有两种不同的类型:ANSI字符集API和UNICODE字符集API,分别对应ANSI字符和UNICODE字符,Windows NT支持两种类型的API,Windows 95/98只支持ANSI字符集API。

在WINDOWS.H头文件和其他Win32 API定义头文件中,凡是与字符有关的API都有两种不同的定义,ANSI字符集API以API 名称加字符“A”表示,UNICODE字符集API以API名称加字符“W”表示,并使用条件编译和宏定义实现自动根据当前字符集使用对应的API定义,例如GetModuleHandle函数的定义(包括在 WINBASE.H头文件中):WINBASEAPIHMODULEWINAPIGetModuleHandleA(LPCSTR lpModuleName);WINBASEAPIHMODULEWINAPIGetModuleHandleW(LPCWSTR lpModuleName);#ifdef UNICODE#define GetModuleHandle GetModuleHandleW#else#define GetModuleHandle GetModuleHandleA#endif // !UNICODE与字符有关的数据结构也有类似的定义。

本教程考虑到汇编语言使用条件汇编会导致不太直观,全部使用ANSI字符集API,这样也可以保证在Windows 95/98和Windows NT环境下的兼容性,所以本教程中许多API名称和数据结构的名称都加有“A”字符,读者可以方便地改用UNICODE字符集API。

四、一个简单的Win32汇编语言程序读者可能一听到“汇编语言”四个字就觉得十分头疼!汇编语言给人的第一印象就是一大堆难以看懂又不直观的指令,而且不结构化,大量的标号、无条件跳转指令(JMP)和条件跳转指令让你难以看懂程序;过程(或者函数)的调用参数传递又不直观,要么直接使用寄存器传递参数,不符合结构化程序设计原则;要么使用堆栈传递参数,又不能有效地检验参数类型……想必Win32汇编语言更麻烦吧!还好,MASM 6.0以上版本的汇编器提供了很多结构化汇编语言伪指令,可以方便地实现汇编语言结构化程序设计,当你看完本教程以后,你可能会感觉到:Win32汇编语言并不比C语言麻烦多少。

(如果读者看不懂本教程中的汇编语言源程序也不要紧,可以对照MASM 6.11的帮助看)和C语言Win32编程需要WINDOWS.H头文件和其他Win32 API定义头文件定义常量、数据结构和API 一样,Win32汇编语言也需要包含文件(INC文件)定义常量、数据结构和API。

不过笔者找了很长时间也没有找到一个完整的可用于Win32汇编语言的WINDOWS.INC文件或者WIN32.INC文件(倒是找到了用于Win16汇编语言的WINDOWS.INC文件),Turbo MASM 5.0中提供的WIN32.INC文件也不完整,只能用于自带的WAP32例子程序,而且与MASM 6.11不太兼容(听说NASM中有完整的WIN32.INC文件,可惜没有找到,也不知道与MASM 6.11是否兼容)。

笔者只好自己定义常量、数据结构和API(根据WINDOWS.H头文件和其他Win32 API定义头文件定义),不过这倒带来了不少好处——可以更好地了解Win32汇编语言的编程方法和原理。

笔者编写了一个简单的Win32汇编语言程序,该程序的功能很简单:在屏幕上显示一个消息框。

本程序只调用了两个API函数:MessageBox函数和ExitProcess函数,程序如下:包含文件(MSGBOX.INC):UINT TYPEDEF DWORDLPSTR TYPEDEF PTR BYTELPCSTR TYPEDEF LPSTRPVOID TYPEDEF PTRHANDLE TYPEDEF PVOIDHWND TYPEDEF HANDLEMB_ICONINFORMATION = 00000040hMB_OK = 00000000hMessageBoxA PROTO stdcall, :HWND,:LPCSTR,:LPCSTR,:UINTExitProcess PROTO stdcall, :UINT源程序(MSGBOX.ASM):.386p.MODEL flat,stdcallINCLUDE MSGBOX.INC.STACK 4096.DATAWindowTitle BYTE 'MsgBox',0Message1 BYTE 'This is a simple MessageBoxWin32 application.',0.CODE_start:INVOKE MessageBoxA,0,ADDR Message1,ADDR WindowTitle,MB_ICONINFORMATION or MB_OKINVOKE ExitProcess,0PUBLIC _startEND汇编连接本程序的命令如下:ml /c /coff /Cp msgbox.asmlink /subsystem:windows /entry:_start msgbox.obj kernel32.lib user32.lib汇编命令中的/c选项表示只汇编,不自动连接;/coff选项表示生成COFF格式的OBJ文件(如果使用Borland的连接器不能使用/coff参数);/Cp选项表示标识符区分大小写。

连接命令中/subsystem:windows选项表示连接器生成普通Windows可执行文件; /entry:_start选项表示程序入口点是_start标识符。

连接时连接KERNEL32.LIB和USER32.LIB引入库。

运行汇编连接后生成的MSGBOX.EXE文件,屏幕上将显示出一个消息框,消息框的标题是“MsgBox”,消息框中的字符串是“This is a simple MessageBox Win32 application.”。

Win32汇编语言源程序应该由.386p伪指令和.MODEL flat,stdcall伪指令开始,指示汇编器汇编386保护模式指令,并使用平坦内存模式(Win32内存模式)和stdcall函数调用方式(Win32标准函数调用方式)。

PROTO伪指令定义函数原型(与C语言中函数原型的定义相似),可以定义函数名、调用方式和参数,INVOKE 伪指令调用由PROTO伪指令定义的函数,可以方便地传递参数和检查参数类型。

MSGBOX.INC文件中使用PROTO伪指令定义API函数,MSGBOX.ASM文件中使用INVOKE伪指令调用API函数,可见MASM 6.0以上版本的汇编器提供的结构化汇编语言伪指令大大简化了Win32汇编语言编程(本程序一条汇编语言指令也没有用到)。

相关文档
最新文档