;Beavis & Butt-head Hock-a-Loogie Trainer

;compiler directives
.386
.model flat,stdcall
option casemap:none

;standard includes
include include\windows.inc
include include\kernel32.inc
include include\user32.inc
includelib lib\kernel32.lib
includelib lib\user32.lib

;Procedures
DlgProc		PROTO :DWORD,:DWORD,:DWORD,:DWORD
Engine_Add      PROTO :DWORD,:DWORD,:DWORD,:DWORD
Engine_Mov      PROTO :DWORD,:DWORD,:DWORD,:DWORD
Engine_Pke	PROTO :DWORD,:DWORD,:DWORD
CheckHotKeys	PROTO

;Id for our dialog (standard is 101)
ID_DIALOG	equ	101

.data
WndCap      db  'Beavis & Butt-head Hock-a-Loogie',0        ;Caption of target process's window
HMODULE     dd  0                                           ;Handle for GetModuleHandle
hProcess    dd  0                                           ;Handle for Process
Dummy       dd  0                                           ;Needed for our TrainerEngine


ScoreAddr   dd  00412F74h				    ;Location where score is saved
LevelAddr   dd  00412FA8h				    ;maximum scorepoints for level stored here
GamePlay    dd  0041458Ch
ScoreBuf    dd  0                                           ;a dword buffer for score

Caption     db  'defiler''s lame trainer-engine.',0         ;caption for msgbox
                                                            ;Error messages:
Err_patch   db  'There was an error while writing to process!',0
Err_open    db  'There was an error while opening process!',0

.code
main:

        invoke  GetModuleHandleA,0                          ;invoke GetModuleHandle
        mov     HMODULE,eax                                 ;to get a handle for the timerproc
                                                            ;and to invoke the dialog

        invoke  SetTimer,HMODULE,123,1000,addr CheckHotKeys ;Set up a timer that will check for hotkeys every 1000ms

        xor     eax, eax
        mov     ax, ID_DIALOG

                                                            ;Create and show the Dialog
        invoke  DialogBoxParamA,HMODULE,eax,0,addr DlgProc,0

        invoke  ExitProcess,0                               ;Exit Trainer after WM_CLOSE has been sent

                                                            ;Here the tiny DialogProc


DlgProc Proc hWin: DWORD, uMsg: DWORD, wParam: DWORD, lParam: DWORD


        .IF uMsg==WM_CLOSE                                  ;Process WM_CLOSE

            invoke  EndDialog,hWin,0                        ;If WM_CLOSE, then end dialog

        .endif
        ret
    ret
DlgProc endp

                                                            ;This procedure will be called every 1000ms
CheckHotKeys    Proc                                        ;to check for HotKeys and activate the TrainerEngine

    pushad                                                  ;saving regs is necessary (i debugged it and it crashed w/o)

        invoke   GetAsyncKeyState,VK_F12                    ;Has F12 been pressed?
        .IF eax==TRUE                                       ;Yes? Great! Then ...
                                                            ;Add 20 points to score
            invoke  Engine_Add,addr WndCap, ScoreAddr, addr ScoreBuf,20
        .endif

        invoke   GetAsyncKeyState,VK_F11                    ;Has F11 been pressed?
        .IF eax==TRUE                                       ;Yes? Great! Then ...
                                                            ;copy value
            invoke  Engine_Mov,addr WndCap, LevelAddr, ScoreAddr, addr ScoreBuf
        .endif

	invoke	GetAsyncKeyState,VK_F9			    ;Was F9 pressed?
	.IF eax==TRUE

	    invoke  Engine_Pke,addr WndCap, GamePlay,1	    ;Ok, so poke some value into some memory
	.endif

    popad                                                   ;restore regs
    ret

CheckHotKeys    endp


Engine_Add	Proc lpWndCap: DWORD, lpBaseAddress: DWORD, lpBuffer: DWORD, nToAdd: DWORD

        invoke  FindWindowExA,0,0,0,lpWndCap                ;Find Window
        invoke  GetWindowThreadProcessId,eax,addr Dummy     ;Get its process Id
                                                            ;Open Process
        
        invoke  OpenProcess,PROCESS_VM_READ or PROCESS_VM_WRITE,0,Dummy
        mov     hProcess,eax                                ;Save Handle
        .IF     eax==FALSE
            invoke  MessageBoxA,0,addr Err_open,addr Caption,MB_ICONWARNING
            ret
        .endif        
                                                            ;Read current value
        invoke  ReadProcessMemory,eax,lpBaseAddress,lpBuffer,4,addr Dummy
        mov     ecx,nToAdd                                  ;ecx = number to add
        mov     ebx,dword ptr [lpBuffer]                    ;move address lpBuffer points to, to ebx
        add     dword ptr [ebx],ecx                         ;and add ecx to the value ebx points to

                                                            ;write new buffer:
        invoke  WriteProcessMemory,hProcess,lpBaseAddress,lpBuffer,4,addr Dummy
        .IF     eax==FALSE
            invoke  MessageBoxA,0,addr Err_patch,addr Caption,MB_ICONWARNING
        .endif

        invoke  CloseHandle,hProcess                        ;close handle for process
        ret

Engine_Add	endp

Engine_Mov	Proc lpWndCap: DWORD, lpSrcAddress: DWORD, lpDstAddress: DWORD, lpBuffer: DWORD

        invoke  FindWindowExA,0,0,0,lpWndCap                ;Find Window
        invoke  GetWindowThreadProcessId,eax,addr Dummy     ;Get its process Id
                                                            ;Open Process
        
        invoke  OpenProcess,PROCESS_VM_READ or PROCESS_VM_WRITE,0,Dummy
        mov     hProcess,eax                                ;Save Handle
        .IF     eax==FALSE
            invoke  MessageBoxA,0,addr Err_open,addr Caption,MB_ICONWARNING
            ret
        .endif        
                                                            ;Read current value
        invoke  ReadProcessMemory,eax,lpSrcAddress,lpBuffer,4,addr Dummy

                                                            ;copy buffer to destaddr:
        invoke  WriteProcessMemory,hProcess,lpDstAddress,lpBuffer,4,addr Dummy
        .IF     eax==FALSE
            invoke  MessageBoxA,0,addr Err_patch,addr Caption,MB_ICONWARNING
        .endif

        invoke  CloseHandle,hProcess                        ;close handle for process
        ret

Engine_Mov	endp

Engine_Pke	Proc lpWndCap: DWORD, lpBaseAddress: DWORD, nNewVal: DWORD

        invoke  FindWindowExA,0,0,0,lpWndCap                ;Find Window
        invoke  GetWindowThreadProcessId,eax,addr Dummy     ;Get its process Id
                                                            ;Open Process
        
        invoke  OpenProcess,PROCESS_VM_READ or PROCESS_VM_WRITE,0,Dummy
        mov     hProcess,eax                                ;Save Handle
        .IF     eax==FALSE
            invoke  MessageBoxA,0,addr Err_open,addr Caption,MB_ICONWARNING
            ret
        .endif        
                                                            ;write nNewVal to BaseAddress:
        invoke  WriteProcessMemory,hProcess,lpBaseAddress,addr nNewVal,4,addr Dummy
        .IF     eax==FALSE
            invoke  MessageBoxA,0,addr Err_patch,addr Caption,MB_ICONWARNING
        .endif

        invoke  CloseHandle,hProcess                        ;close handle for process
        ret

Engine_Pke	endp

end main