0
点赞
收藏
分享

微信扫一扫

MASM32编程访问结构体成员要注意的一点


今天继续用MASM32编写调用Windows API函数GetNativeSystemInfo来检测Windows操作系统是32位还是64位的程序。

修改完善形成了下面的代码:

;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; 32or64.asm
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

.586
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

;sssssssssssssssssssssssssssssssssssssss
;.const
;sssssssssssssssssssssssssssssssssssssss
;PROCESSOR_ARCHITECTURE_INTEL equ 0 ;x86
;PROCESSOR_ARCHITECTURE_ARM equ 5 ;ARM
;PROCESSOR_ARCHITECTURE_IA64 equ 6 ;基于 Intel Itanium 的
;PROCESSOR_ARCHITECTURE_AMD64 equ 9 ;x64 (AMD 或 Intel)
PROCESSOR_ARCHITECTURE_ARM64 equ 12 ;ARM64
;PROCESSOR_ARCHITECTURE_UNKNOWN equ 0ffffh ;未知体系结构。


_SYSTEM_INFO STRUCT
UNION
dwOemId DWORD ?
STRUCT
wProcessorArchitecture WORD ?
wReserved WORD ?
ENDS
ENDS
dwPageSize DWORD ?
lpMinimumApplicationAddress DWORD ?
lpMaximumApplicationAddress DWORD ?
dwActiveProcessorMask DWORD ?
dwNumberOfProcessors DWORD ?
dwProcessorType DWORD ?
dwAllocationGranularity DWORD ?
wProcessorLevel WORD ?
wProcessorRevision WORD ?
_SYSTEM_INFO ENDS

;sssssssssssssssssssssssssssssssssssssss
.data
;sssssssssssssssssssssssssssssssssssssss
g_szCaption db "Windows",0
g_sz32Bit db "32位",0
g_sz64Bit db "64位",0
g_szGetNativeSystemInfo db "GetNativeSystemInfo", 0
g_szkernel32Dll db "kernel32.dll", 0
g_szFailGetModuleHandle db "GetModuleHandle失败", 0
g_szFailGetProcAddress db "GetProcAddress失败", 0
g_szFailGetNativeSystemInfo db "GetNativeSystemInfo失败", 0
g_lpfnGetNativeSystemInfo dword ?
g_lpSI dword ? ; SYSTEM_INFO


;sssssssssssssssssssssssssssssssssssssss
.code
;sssssssssssssssssssssssssssssssssssssss
start:
invoke GetModuleHandle, OFFSET g_szkernel32Dll
.if eax==NULL
mov eax, OFFSET g_szFailGetModuleHandle
.else
invoke GetProcAddress, eax, OFFSET g_szGetNativeSystemInfo
.IF eax==NULL
mov eax, OFFSET g_szFailGetProcAddress
.ELSE
mov g_lpfnGetNativeSystemInfo, eax
push offset g_lpSI
call g_lpfnGetNativeSystemInfo
mov eax, g_lpSI
movzx eax, (SYSTEM_INFO ptr [eax]).wProcessorArchitecture
.if (eax==PROCESSOR_ARCHITECTURE_IA64) || (eax==PROCESSOR_ARCHITECTURE_AMD64) || (eax==PROCESSOR_ARCHITECTURE_ARM64)
mov eax, OFFSET g_sz64Bit
.else
mov eax, OFFSET g_sz32Bit
.endif
.ENDIF
.endif
invoke MessageBox, NULL, eax, OFFSET g_szCaption, MB_OK
invoke ExitProcess, NULL
end start

代码顺利汇编和连接,生成了EXE,但运行时出错:

MASM32编程访问结构体成员要注意的一点_操作系统版本

 用OllDbg跟踪调试:

MASM32编程访问结构体成员要注意的一点_操作系统版本_02

引发问题的代码是:

movzx eax,  (SYSTEM_INFO ptr [eax]).wProcessorArchitecture

回溯起来问题出在上一行代码:

mov   eax, g_lpSI

根源则在于汇编程序中的寻址方式,由于SYSTEM_INFO结构体的定义是公开透明的,我们可以手工算出成员的偏移地址来进行访问,但为了保证通用性和灵活性,一般我们是用基址+变址的方式来访问结构体成员的,把代码改成:

mov   eax, offset g_lpSI

这样程序就能顺利运行并给出结果:

MASM32编程访问结构体成员要注意的一点_Windows_03

 再进一步完善:

;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; FileName: CpuArch.asm
; Function: Show CPU Architecture with API GetNativeSystemInfo
; Author: PurpleEndurer
; DevEnv: Windows 7 Ultimate 64bit + MASM32
;
; Log:
;---------------------------------------------------------------
; 20221126 Created
; 20221127 Added c_showMoreInfo, getCpuArcInfo(), OK!
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
.586
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

;sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
;proto
;sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
_GetNativeSystemInfo TYPEDEF proto :DWORD
lpfnGetNativeSystemInfo TYPEDEF Ptr _GetNativeSystemInfo

getCpuArcInfo proto

;sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
;.const
;sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
;PROCESSOR_ARCHITECTURE_INTEL equ 0 ;x86
;PROCESSOR_ARCHITECTURE_ARM equ 5 ;ARM
;PROCESSOR_ARCHITECTURE_IA64 equ 6 ;基于 Intel Itanium 的
;PROCESSOR_ARCHITECTURE_AMD64 equ 9 ;x64 (AMD 或 Intel)
PROCESSOR_ARCHITECTURE_ARM64 equ 12 ;ARM64
;PROCESSOR_ARCHITECTURE_UNKNOWN equ 0ffffh ;未知体系结构。
c_showMoreInfo equ 1

_SYSTEM_INFO STRUCT
UNION
dwOemId DWORD ?
STRUCT
wProcessorArchitecture WORD ?
wReserved WORD ?
ENDS
ENDS
dwPageSize DWORD ?
lpMinimumApplicationAddress DWORD ?
lpMaximumApplicationAddress DWORD ?
dwActiveProcessorMask DWORD ?
dwNumberOfProcessors DWORD ?
dwProcessorType DWORD ?
dwAllocationGranularity DWORD ?
wProcessorLevel WORD ?
wProcessorRevision WORD ?
_SYSTEM_INFO ENDS

;sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
.data
;sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
g_szCaption db "Windows",0
g_szGetNativeSystemInfo db "GetNativeSystemInfo", 0
g_szkernel32Dll db "kernel32.dll", 0
g_szFailGetModuleHandle db "GetModuleHandle失败", 0
g_szFailGetProcAddress db "GetProcAddress失败", 0
g_szFailGetNativeSystemInfo db "GetNativeSystemInfo失败", 0

if c_showMoreInfo eq 0
g_sz32Bit db "32位",0
g_sz64Bit db "32位",0
else
g_szPROCESSOR_ARCHITECTURE_INTEL db "x86", 0 ; equ 0
g_szPROCESSOR_ARCHITECTURE_ARM db "ARM", 0 ; equ 5
g_szPROCESSOR_ARCHITECTURE_IA64 db "IA64",0 ;equ 6,基于 Intel Itanium 的
g_szPROCESSOR_ARCHITECTURE_AMD64 db "x64 (AMD 或 Intel)", 0; equ 9
g_szPROCESSOR_ARCHITECTURE_ARM64 db "ARM64", 0 ;equ 12
g_szPROCESSOR_ARCHITECTURE_UNKNOWN db "Unknown", 0 ;equ 0ffffh,未知体系结构。
endif ;c_showMoreInfo

g_lpfnGetNativeSystemInfo lpfnGetNativeSystemInfo ? ; dword ?
g_lpSI dword ? ; SYSTEM_INFO


;sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
.code
;sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
start:
invoke GetModuleHandle, OFFSET g_szkernel32Dll
.if eax==NULL
mov eax, OFFSET g_szFailGetModuleHandle
.else
invoke GetProcAddress, eax, OFFSET g_szGetNativeSystemInfo
.IF eax==NULL
mov eax, OFFSET g_szFailGetProcAddress
.ELSE
mov g_lpfnGetNativeSystemInfo, eax

;push OFFSET g_lpSI
;call g_lpfnGetNativeSystemInfo
invoke g_lpfnGetNativeSystemInfo, OFFSET g_lpSI

mov eax, OFFSET g_lpSI ; mov eax, g_lpSI will cause an exception!
movzx eax, [eax+SYSTEM_INFO.wProcessorArchitecture] ;movzx eax, (SYSTEM_INFO ptr [eax]).wProcessorArchitecture

invoke getCpuArcInfo
.ENDIF
.endif
invoke MessageBox, NULL, eax, OFFSET g_szCaption, MB_OK
invoke ExitProcess, NULL


getCpuArcInfo proc ; dwCpuArc: dword
; input : eax=CpuArchitecture
; Output: eax=offset address of Cpu Architecture infomation string
IF c_showMoreInfo eq 0
.if (eax==PROCESSOR_ARCHITECTURE_IA64) || (eax==PROCESSOR_ARCHITECTURE_AMD64) || (eax==PROCESSOR_ARCHITECTURE_ARM64)
mov eax, OFFSET g_sz64Bit
.else
mov eax, OFFSET g_sz32Bit
.endif
ELSE
.if eax==PROCESSOR_ARCHITECTURE_INTEL
mov eax, OFFSET g_szPROCESSOR_ARCHITECTURE_INTEL
.elseif eax==PROCESSOR_ARCHITECTURE_ARM
mov eax, OFFSET g_szPROCESSOR_ARCHITECTURE_ARM
.elseif eax==PROCESSOR_ARCHITECTURE_IA64
mov eax, OFFSET g_szPROCESSOR_ARCHITECTURE_IA64
.elseif eax==PROCESSOR_ARCHITECTURE_AMD64
mov eax, OFFSET g_szPROCESSOR_ARCHITECTURE_AMD64
.elseif eax==PROCESSOR_ARCHITECTURE_ARM64
mov eax, OFFSET g_szPROCESSOR_ARCHITECTURE_ARM64
.else
mov eax, OFFSET g_szPROCESSOR_ARCHITECTURE_UNKNOWN
.endif
ENDIF ;c_showMoreInfo
ret
getCpuArcInfo endp

end start

程序运行结果:

MASM32编程访问结构体成员要注意的一点_Windows_04

 如果用C++来完成,就没有这么折腾了,用Microsoft Visual Studio  2019来实现的代码如下:

// 32or64.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include "windows.h"
#include <iostream>
#include "sysinfoapi.h"

int main()
{
SYSTEM_INFO si;
int iCpuArc;

GetNativeSystemInfo(&si);

iCpuArc = si.wProcessorArchitecture;
std::cout << "si.wProcessorArchitecture=";
std::cout << iCpuArc;
std::cout << "\nArchitecture:";
switch (iCpuArc)
{
case PROCESSOR_ARCHITECTURE_INTEL:
std::cout << "x86\n";
break;
case PROCESSOR_ARCHITECTURE_ARM:
std::cout << "ARM\n";
break;
case PROCESSOR_ARCHITECTURE_IA64:
std::cout << "IA64\n";
break;
case PROCESSOR_ARCHITECTURE_AMD64:
std::cout << "x64 (AMD 或 Intel)\n";
break;
case PROCESSOR_ARCHITECTURE_ARM64:
std::cout << "ARM64\n";
break;
default:
std::cout << "UNKNOWN\n";
}
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

运行结果如下:

MASM32编程访问结构体成员要注意的一点_MASM32_05

 

 

举报

相关推荐

0 条评论