Archive for 十月, 2008

其它内存管理函数

汇编&逆向 | Posted by 老沙
10月 19 2008

1.填充和移动内存

mov esi,offset szSource
mov edi,offset szDest
mov ecx,dwSize
cld
rep movsb

以上代码实现从szSource开始的dwSize大小的内存块移动到szDest处

xor eax,eax
mov edi,offset szDest
mov ecx,dwSize
cld
rep stosb

以上代码实现szDest处开始的dwSize字节填充为0,如果把xor eax,eax换成mov al,xx 那上边的代码将实现将内存块填充为xx

以上功能对应的API如下:

invoke RtlMoveMemory,offset szDest,offset szSource,dwSize ;移动内存
invoke RtlFillMemory,offset szDest,dwSize,dbFill ;以dbFill填充内存块
invoke RtlZeroMemory,offset szDest,dwSize ;以0填充内存块

2.内存状态测试

invoke IsBadCodePtr,lpMemory
invoke IsBadReadPtr,lpMemory,dwSize
invoke IsBadWritePtr,lpMemory,dwSize
invoke IsBadStringPtr,lpMemory,dwSize

IsBadCodePtr:函数测试指针指向的单个字节是否可读,如果可读返回0,否则返回非0值
IsBadReadPtr:测试某段内存是否可读,如果这段内存的所有字节全可读则返回0,否则返回非0值
IsBadWritePtr:测试某段内存是否可写,如果内存段全都可写则返回0,否则返回非0值
IsBadStringPtr:测试一个指向以0结尾的字符串是否可读,dwSize为字符串最大长度,如果字符串包含结尾的0全是可读的,返回0,否则返回非0值,缓冲区中剩余的字节则不予测试

堆管理函数

汇编&逆向 | Posted by 老沙
10月 15 2008

堆管理函数
1.私有堆的创建和释放
私有堆的创建

invoke HeapCreate,flOptions,dwInitialSize,dwMaximumSize
.if eax && (eax<0c0000000h)
mov hHeap,eax
.endif

flOptions指定堆属性,有两个值
HEAP_NO_SERIALIZE:标志私有堆不进行独占检测
HEAP_GENERATE_EXCEPTIONS:指定函数失败的返回值,不指定失败返回NULL
dwInitialSize指定创建堆时分配的物理内存
dwMaximumSize为堆自动扩展的最大值.为0则没有最大限制,非0时在堆中申请的内存块不能大于7FFF8h(524K)

私有堆的释放

invoke HeapDestroy,hHeap

将释放堆中所有的内存块.成功运行返回TRUE,当进程终止时系统也会自动调用此函数

2.堆中分配和释放内存块
堆中分配内存块

invoke HeapAlloc,hHeap,dwFlags,dwBytes
.if eax && (eax<0c0000000h)
mov lpMemory,eax
.endif

hHeap:是创建堆时的句柄
dwFlags有三个值
HEAP_NO_SERIALIZE:不进行独占检测,如果创建堆时用了,这里就可以省了
HEAP_GENERATE_EXCEPTIONS:失败返回出错原因,而不仅是一个NULL,创建堆时用了,这里也可以省了
HEAP_ZERO_MEMORY:将分配内存用0初始化
dwBytes:是要分配的内存块的字节数
分配成功返回值是指向内存块第一个字节的指针,失败返回错误代码或NULL,要看dwFlags
STATUS_NO_MEMORY:取值为0c0000017h表示内存不够
STATUS_ACCESS_VIOLATION:取值为0c0000005h表示参数不正确或堆被破坏
在堆中分配内存块只能是固定地址的内存块.

堆中释放内存块

invoke HeapFree,hHeap,dwFlags,lpMemory

hHeap:堆句柄
dwFlags:可以使用HEAP_NO_SERIALIZE
lpMemory:是HeapAlloc函数返回的内存块指针
成功返回非0值,失败返回0

堆中调整内存块大小

invoke HeapReAlloc,hHeap,dwFlags,lpMemory,dwBytes
.if eax && (eax<0c0000000h)
mov lpMemory,eax
.endif

hHeap:堆句柄
dwFlags四个值
HEAP_GENERATE_EXCEPTIONS:返回值
HEAP_NO_SERIALIZE:独占检测
HEAP_ZERO_MEMORY:初始化为0
HEAP_REALLOC_IN_PLACE_ONLY:分配内存时不可移动内存块,使用此标志,指针必定和原来相同
lpMemory:为堆中内存块的指针
dwBytes:要改变的内存块的大小的字节数

3.其它堆管理函数
HeapLock,HeapUnlock,GetProcessHeaps,GetProcessHeap,HeapCompact,HeapSize,
HeapValidate,HeapWalk.

invoke GetProcessHeaps,NumberOfHeaps,lpHeaps

NumberOfHeaps:指定了缓冲区可以存放句柄的数量
lpHeaps:是一个指针,指向用来接收堆句柄的缓冲区,缓冲区长度应该等于NumberOfHeaps*4
执行后函数返回进程中所有堆的句柄到缓冲区中,也包括默认堆的句柄

.repeat
invoke HeapWalk,hHeap,lpEntry
push eax
pop eax
.until !eax

hHeap:是堆的句柄
lpEntry:指向一个句含有PROCESS_HEAP_ENTRY结构的缓冲区
每次执行返回一个PROCESS_HEAP_ENTRY的结构块信息,如果还有其他的内存块,函数返回TRUE,程序一直循环调用直到返回FALSE为止,在多线程的程序中使用,必须先使用HeapLock函数,否则会调用失败.

invoke HeapValidate,hHeap,dwFlags,lpMemory

验证堆的完整性或堆中某个内存块的完整性
lpMemory为NULL函数顺序验证堆中所有的内存块,如果lpMemory指定了一个内存块,则只验证这个内存块
dwFlags:可以指定HEAP_NO_SERIALIZE,独占标志
如果所有内存块都完好无损,返回非0值,否则返回0

invoke HeapLock,hHeap
invoke HeapUnlock,hHeap

销定和解销堆,主要用于线程同步,成功返回非0值,否则返回0,在程序中一般用HEAP_NO_SERIALIZE来控制

invoke HeapCompact,hHeap,dwFlags

合并堆中的空闲内存块并释放不在使用中的内存页面

invoke HeapSize,hHeap,dwFlags,lpMemory

返回堆中某个内存块大小lpMemory指定了需要返回大小的内存块,成功返回内存块大小,失败返回-1

虚拟内存管理函数

汇编&逆向 | Posted by 老沙
10月 14 2008

虚拟内存管理函数
VirtualAlloc,VirtualFree – 地址空间分配和释放
VirtualLock,VirtualUnlock – 对内存页进行销定和解锁
VirtualQuery,VirtualQueryEx – 查询内存页的状态
VirtualProtect,VirtualProtectEx – 改变内存页的保护属性

1.保留和释放地址空间

invoke VirtualAlloc,lpAddress,dwSize,flAllocationType,flProtect

lpAddress:指定要保留或提交的内存地址,为NULL时系统自动分配一个地址
dwSize:表示函数分配的地址范围大小,单位字节
flAlloctiontype可以取的标志有三个
MEM_COMMIT:为指定地址空间提交物理内存
MEM_RESERVE:保留指定地址空间,不分配物理内存
MEM_TOP_DOWN:尽可能使用高端的地址空间
flProtect可以取的标志有六个
PAGE_READONLY:为以提交的物理内存的址空间设定只读属性
PAGE_READWRITE:为以提交的物理内存设定为可读写属性
PAGE_EXECUTE:设定为可执行属性
PAGE_EXECUTE_READ:为物理内存设定可读和可执行属性
PAGE_EXECUTE_READWRITE:为内存设定为可读写和可执行属性
PAGE_NOACCESS:为保留的地址空间设定为不可存取模式
函数执行成功会返回一个指向被保留地址范围开始位置的指针,执行失败返回NULL

invoke VirtualFree,lpAddress,dwSize,dwFreeType

lpAddress与dwSize:为指定地址和空间的大小,与VirtualAlloc相同
dwFreeType可以的标志有两个
MEM_DECOMMIT:为一个以提交的物理内存的地址空间解除提交
MEM_RELEASE:释放保留的址址空间

例:

invoke VirtualAlloc,NULL,10485760,MEM_RESERVE,PAGE_NOACCESS
.if eax
mov lpAddress,eax
.endif

空间的分配方式用MEM_RESERVE保留指定地址空间,不分配物理内存,是无法访问的,所以保护属性必须使用PAGE_NOACCESS,以上代码保留10M大小的空间,保留地址并不保证将来有可用内存来提交给这些地址

invoke VirtualFree,lpAddress,0,MEM_RELEASE

lpAddress是VirtualAlloc返回的指针,释放保留内存时dwSize必须为0,释放一个地址空间中的所有页面必须是同一个状态,否则释放操作会失败.

2.使用保留的地址空间

invoke VirtualAlloc,lpAddress,4096,MEM_COMMIT,PAGE_READWRITE
.if eax
mov lpMemory,eax
.endif

保留地址内存可以按一页的大小被分次提交,也可以一次提交所有的保留地址,当内存被提交时,可以被分配为物理内存页,也有可以被分配在页文件中,在提交时lpAddress不能为NULL,要指定一个特定的地址来准确地指示被保留的哪一页会被提交.属性可以设定成可访问的,成功返回第一页起始线程的地址,失败返回NULL

invoke VirtualAlloc,NULL,dwSize,MEM_RESERVE or MEM_COMMIT,PAGE_READWRITE
.if eax
mov lpMemory,eax
.endif

这种方法与GlobalAlloc函数直接分配一块内存没有多大区别,只是可以指定分配的内存块地址

invoke VirtualFree,lpMemory,dwSize,MEM_DECOMMIT

以上代码为解除提交,让它们从提交状态返回到保留状态,函数的操作对象是整个页面,如果指定的内存范围不是整个页面,函数会自动将整个范围同属一个页面的地址全部解除提交.

3.内存页的保护和锁定

invoke VirtualProtect,lpAddress,dwSize,flNewProtect,lpflOldProtect

flNewProtect:是新的保护方式,取值可以参考VirtualAlloc的flProtect的标志
lpOldProtect:是指向一个双字的指针,函数会在这里返回原来的保护方式,如果不需要可以设置为NULL

invoke VirtualLock,lpAddress,dwSize
invoke VirtualUnlock,lpAddress,dwSize

锁定的意思是将指定内存页保留在物理内存中,不许将它交换到磁盘页文件中,同时锁定的内数不能超过30个

超类化 罗老板的源码

汇编&逆向 | Posted by 老沙
10月 12 2008

super.asm:

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .386
    .model flat, stdcall
    option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include    windows.inc
include    user32.inc
includelib  user32.lib
include    kernel32.inc
includelib  kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ 等值定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN  equ  1000
DLG_MAIN  equ  1000
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .data?

hInstance  dd  ?
hWinMain  dd  ?
lpOldProcEdit  dd  ?

    .const
szAllowedChar  db  '0123456789ABCDEFabcdef',08h
szEditClass  db  'Edit',0
szClass    db  'HexEdit',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; HexEdit控件的新窗口过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcEdit  proc  uses ebx edi esi hWnd,uMsg,wParam,lParam

    mov  eax,uMsg
    .if  uMsg ==  WM_CHAR
      mov  eax,wParam
      mov  edi,offset szAllowedChar
      mov  ecx,sizeof szAllowedChar
      repnz  scasb
      .if  ZERO?
        .if  al > '9'
          and  al,not 20h
        .endif
        invoke  CallWindowProc,lpOldProcEdit,hWnd,uMsg,eax,lParam
        ret
      .endif
    .else
      invoke  CallWindowProc,lpOldProcEdit,hWnd,uMsg,wParam,lParam
      ret
    .endif
    xor  eax,eax
    ret

_ProcEdit  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 基于Edit类建立一个新的类:HexEdit
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_SuperClass  proc
    local  @stWC:WNDCLASSEX

    mov  @stWC.cbSize,sizeof @stWC
    invoke  GetClassInfoEx,NULL,addr szEditClass,addr @stWC
    push  @stWC.lpfnWndProc
    pop  lpOldProcEdit
    mov  @stWC.lpfnWndProc,offset _ProcEdit
    push  hInstance
    pop  @stWC.hInstance
    mov  @stWC.lpszClassName,offset szClass
    invoke  RegisterClassEx,addr @stWC
    ret

_SuperClass  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcDlgMain  proc  uses ebx edi esi hWnd,wMsg,wParam,lParam

    mov  eax,wMsg
;********************************************************************
    .if  eax ==  WM_CLOSE
      invoke  EndDialog,hWnd,NULL
;********************************************************************
    .else
      mov  eax,FALSE
      ret
    .endif
    mov  eax,TRUE
    ret

_ProcDlgMain  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>&g

t;>>>>>>>>>>>>>>>>>>>
start:
    invoke  GetModuleHandle,NULL
    mov  hInstance,eax
    invoke  _SuperClass
    invoke  DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,NULL
    invoke  ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    end  start

super.rc:

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include    <resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define  ICO_MAIN  1000
#define  DLG_MAIN  1000
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN  ICON    "Main.ico"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DLG_MAIN DIALOG 107, 102, 126, 82
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "SuperClass"
FONT 9, "宋体"
{
CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,5,115,12
CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,20,115,12
CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,35,115,12
CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,50,115,12
CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,65,115,12
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

标准内存管理函数

汇编&逆向 | Posted by 老沙
10月 09 2008

标准内存管理函数
GlobalAlloc,GlobalFree,GlobalReAlloc,GlobalLock,GlobalUnlock,GlobalDiscard,GlobalFlags,GlobalHandle,GlobalSize

1.固定的内存块

invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,dwBytes
.if eax
mov lpMemory,eax
.endif

申请失败eax返回NULL,成功返回指向申请内存起始地址的指针.GPTR

释放固定内存块

invoke GlobalFree,lpMemory

释放成功返回NULL,返否返回输入的lpMemory

改变内存块大小

invoke GlobalReAlloc,lpMemory,dwBytes,uFlags
.if eax
mov lpNewMemory,eax
.endif

lpMemory是先前申请的内存指针,dwBytes是新大小,uFlags可以是空
uFlags来规定是否允许移动内存块,当为GMEM_MOVEABLE选项时,如果需要移动内存块windows会在其它地方新开一个内存块,并把原来的内容自动复制到新内存中,这时函数会返回一个新的指针,原来的指针作废
如果不指定GMEM_MOVEABLE,当后面的空间不足时,函数失败并返回NULL,原来的指针继续有效.
改变内存大小时,建意使用以下代码

invoke GlobalReAlloc,lpMemory,dwBytes,GMEM_ZEROINIT or GMEM_MOVEABLE
.if eax
mov lpMemory,eax
.endif

2.可移动的内存块
申请可移动的内存块

invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,dwBytes
.if eax
mov hMemory,eax
.endif

GMEM_MOVEABLE or GMEM_ZEROINIT = GHND
申请失败eax返回NULL,成功返回一个句柄.可移动内存块不能超过65536个,固定内存块数量无限制

销定可移动内存:

invoke GlobalLock,hMemory
.if eax
mov lpMemory,eax
.endif

销定失败返回NULL,成功返回一个指针
当不使用时要解销

invoke GlobalUnlock,hMemory

解销成功返回非0值

释放可移动内存块

invoke GlobalFree,hMemory

释放成功返回NULL

调整可移动内存块大小

invoke GlobalReAlloc,hMemory,dwBytes,GHND

如果成功返回hMemory,失败返回NULL
注意最好先解销再调整大小

3.可丢弃的内存块
可丢弃的内存块必须是可移动的内存块

invoke GlobalAlloc,GHND or GMEM_DISCARDABLE,dwBytes
.if eax
mov hMemory,eax
.endif

如果GlobalLock内存返回NULL,说明内存以被丢弃了,但句柄还是有效的,如果还要使用这个句柄,可以使用
GlobalReAlloc来重新分配内存,当销定计数为0时,可以使用GlobalDiscard主动将它丢弃.

4.获取内存块的信息
GlobalFlags主要用来取得可移动内存的计数,也可以检测可丢弃内存是否被丢弃.

invoke GlobalFlags,hMemory
and eax,GMEM_LOCKCOUNT
mov dwLockCount,eax

返回值不是GMEM_INVALID_HANDLE说明调用成功,这时返回值低8位是内存块的销定计数
GMEM_DISCARDABLE 表示内存块是可丢弃内存块
GMEM_DISCARDED 表示内存块以被失弃

GlobalHandle可以从GlobalLock得到的lpMemory值获取对应的hMemory
GlobalSize可以获取一个内存块的尺寸

子类化 罗老板的源码

汇编&逆向 | Posted by 老沙
10月 08 2008

subclass.asm:

    .386
    .model flat, stdcall
    option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include    windows.inc
include    user32.inc
includelib  user32.lib
include    kernel32.inc
includelib  kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ 等值定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN  equ  1000
DLG_MAIN  equ  1000
IDC_HEX    equ  1001
IDC_DEC    equ  1002
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .data?
hInstance  dd  ?
hWinMain  dd  ?
dwOption  dd  ?
lpOldProcEdit  dd  ?

    .const
szFmtDecToHex  db  '%08X',0
szFmtHexToDec  db  '%u',0
szAllowedChar  db  '0123456789ABCDEFabcdef',08h
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; IDC_HEX编辑框的新窗口过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcEdit  proc  uses ebx edi esi hWnd,uMsg,wParam,lParam

    mov  eax,uMsg
    .if  uMsg ==  WM_CHAR
      mov  eax,wParam
      mov  edi,offset szAllowedChar
      mov  ecx,sizeof szAllowedChar
      repnz  scasb
      .if  ZERO?
        .if  al > '9'
          and  al,not 20h
        .endif
        invoke  CallWindowProc,lpOldProcEdit,hWnd,uMsg,eax,lParam
        ret
      .endif
    .else
      invoke  CallWindowProc,lpOldProcEdit,hWnd,uMsg,wParam,lParam
      ret
    .endif
    xor  eax,eax
    ret

_ProcEdit  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算16进制到10进制
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_HexToDec  proc
    local  @szBuffer[512]:byte

    invoke  GetDlgItemText,hWinMain,IDC_HEX,addr @szBuffer,sizeof @szBuffer
    lea  esi,@szBuffer
    cld
    xor  eax,eax
    mov  ebx,16
    .while  TRUE
      movzx  ecx,byte ptr [esi]
      inc  esi
      .break  .if ! ecx
      .if  cl > '9'
        sub  cl,'A' – 0ah
      .else
        sub  cl,'0'
      .endif
      mul  ebx
      add  eax,ecx
    .endw
    invoke  wsprintf,addr @szBuffer,addr szFmtHexToDec,eax
    invoke  SetDlgItemText,hWinMain,IDC_DEC,addr @szBuffer
    ret

_HexToDec  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算10进制到16进制
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DecToHex  proc
    local  @szBuffer[512]:byte

    invoke  GetDlgItemInt,hWinMain,IDC

_DEC,NULL,FALSE
    invoke  wsprintf,addr @szBuffer,addr szFmtDecToHex,eax
    invoke  SetDlgItemText,hWinMain,IDC_HEX,addr @szBuffer
    ret

_DecToHex  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcDlgMain  proc  uses ebx edi esi hWnd,wMsg,wParam,lParam

    mov  eax,wMsg
;********************************************************************
    .if  eax ==  WM_CLOSE
      invoke  EndDialog,hWnd,NULL
;********************************************************************
    .elseif  eax ==  WM_INITDIALOG
      mov  eax,hWnd
      mov  hWinMain,eax
      invoke  SendDlgItemMessage,hWnd,IDC_HEX,EM_LIMITTEXT,8,0
      invoke  SendDlgItemMessage,hWnd,IDC_DEC,EM_LIMITTEXT,10,0
      invoke  GetDlgItem,hWnd,IDC_HEX
      invoke  SetWindowLong,eax,GWL_WNDPROC,addr _ProcEdit
      mov  lpOldProcEdit,eax
;********************************************************************
    .elseif  eax ==  WM_COMMAND
      mov  eax,wParam
      .if  ! dwOption
        mov  dwOption,TRUE
        .if  ax ==  IDC_HEX
          invoke  _HexToDec
        .elseif  ax ==  IDC_DEC
          invoke  _DecToHex
        .endif
        mov  dwOption,FALSE
      .endif
    .else
      mov  eax,FALSE
      ret
    .endif
    mov  eax,TRUE
    ret

_ProcDlgMain  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
    invoke  GetModuleHandle,NULL
    mov  hInstance,eax
    invoke  DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,NULL
    invoke  ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    end  start

subclass.rc

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include    <resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define  ICO_MAIN  1000
#define  DLG_MAIN  1000
#define IDC_HEX    1001
#define IDC_DEC    1002
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN  ICON    "Main.ico"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DLG_MAIN DIALOG 107, 102, 129, 42
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Hex <> Dec"
FONT 9, "宋体"
{
LTEXT "Hex", -1, 7, 9, 15, 8
EDITTEXT IDC_HEX, 27, 7, 94, 12
LTEXT "Dec", -1, 7, 26, 15, 8
EDITTEXT IDC_DEC, 27, 24, 94, 12, ES_NUMBER
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

QueryPerformanceCounter 微秒计数器

汇编&逆向 | Posted by 老沙
10月 06 2008

QueryPerformanceCounter 可以取得开机以来64位的时间计数值
QueryPerformanceFrequency 取得计算机每秒钟的计数值,和CPU速度有关

Timer.asm:

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .386
    .model flat,stdcall
    option casemap:none
; Include 文件定义
include    windows.inc
include    user32.inc
includelib  user32.lib
include    kernel32.inc
includelib  kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ID_TIMER1  equ  1
DLG_MAIN  equ  1
IDC_COUNT  equ  101
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
dw1m    dd 1000000
ddcc1  db "%d 微秒", 0
buffer db 512 dup(?)

num1 dq 333
num2 dq 3
res dd 0

    .data?
hInstance  dd    ?
tick1    dd    ?
dqtick1  dq  ?
dqtick2  dq  ?
dqFreq  dq  ?
dqTime  dq  ?
buf db 200 dup(?)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_ProcDlgMain  proc  uses ebx edi esi,hWnd,uMsg,wParam,lParam
    mov  eax,uMsg
    .if  eax ==  WM_TIMER
      mov  eax,wParam
      .if  eax == ID_TIMER1
        invoke  MessageBeep,-1
      .endif
    .elseif  eax ==  WM_INITDIALOG
      invoke QueryPerformanceCounter,addr dqtick1
      .while 1
        add edi,1
        .break .if edi > 100000000
        ;.continue
      .endw
      invoke QueryPerformanceCounter,addr dqtick2
      invoke QueryPerformanceFrequency,addr dqFreq
      mov eax,DWORD ptr dqtick1
      mov edx,DWORD ptr dqtick1+4
      sub DWORD ptr dqtick2,eax
      sbb DWORD ptr dqtick2+4,edx
      finit
      fild dqFreq
      fild dqtick2
      fimul dw1m
      fdivr
      fistp dqTime
      invoke wsprintf,addr buf,addr ddcc1,dqTime
      invoke SendDlgItemMessage,hWnd,IDC_COUNT,WM_SETTEXT,NULL,addr buf
    .elseif eax ==  WM_COMMAND
      mov  eax,wParam
      .if ax == IDOK
      invoke QueryPerformanceCounter,addr dqtick1
      .while 1
        add edi,1
        .break .if edi > 100000000
        ;.continue
      .endw
      invoke QueryPerformanceCounter,addr dqtick2
      invoke QueryPerformanceFrequency,addr dqFreq
      mov eax,DWORD ptr dqtick1
      mov edx,DWORD ptr dqtick1+4
      sub DWORD ptr dqtick2,eax
      sbb DWORD ptr dqtick2+4,edx
      finit
      fild dqFreq
      fild dqtick2
      fimul dw1m
      fdivr
      fistp dqTime
      invoke wsprintf,addr buf,addr ddcc1,dqTime
      invoke SendDlgItemMessage,hWnd,IDC_COUNT,WM_SETTEXT,NULL,addr buf
      .endif
    .elseif  eax ==  WM_CLOSE
      invoke  EndDialog,hWnd,NULL
    .else
      mov  eax,FALSE
      ret
    .endif
    mov  eax,TRUE
    ret

_ProcDlgMain  endp

start:
    invoke  GetModuleHandle,NULL
    mov  hInstance,eax
    invoke  DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,NULL
    invoke  ExitProcess,NULL
    end  start

Timer.rc:

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>&

gt;>>>>>>>>>>>>>>>>>>>>>
#include <resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define DLG_MAIN 1
#define ICO_1 1
#define IDC_COUNT 101
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_1 ICON "1.ico"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DLG_MAIN DIALOG 70, 110, 120, 70
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "1+1 1亿次 小杰的博客"
FONT 9, "宋体"
{
LTEXT "计数:", -1, 35, 16, 25, 10
LTEXT "", IDC_COUNT, 62, 16, 60, 10
DEFPUSHBUTTON "开始", IDOK, 35, 36, 50, 20
}