Auto-Assembler

The Auto-Assembler allows you to write ASM scripts that are composed of more than just raw ASM. For example, auto-assemble scripts allow automatic allocation of memory and modification of page protections, as well as full label support. The Injection Manager, on the other hand, is designed to be simpler to use. To open the Auto-Assembler, select the Tools/Auto-Assembler menu item or press Ctrl-U.

 

Commands

The following table explains each command.

Command Description
LABEL( IDENTIFIER )

Denotes an identifier (IDENTIFIER) as a label.
Labels can be used in command operands and to denote the address of code.
For example, with the command Label( MyLabel ) anywhere in the script, it is valid to write:

MyLabel : ; Indicates the starting address of the next line of code.
mov eax, [gamex86.dll+0024FE8C]
mov ecx, MyLabel ; Moves the value of MyLabel into ECX.
mov ecx, DWORD PTR DS: [MyLabel+C] ; Moves the value at the address of MyLabel (plus 12 bytes) into ECX.
jmp MyLabel ; Goes to MyLabel.

If MyLabel becomes address 0x1030015, the final code might become:
01030015: MOV EAX, DWORD PTR DS:[124FE8C]
0103001B: MOV ECX, 1030015
01030021: MOV ECX, DWORD PTR DS:[1030021]
01030027: JMP 01030015

When a label is declared with this command, it has no initial address. Its actual address is determined by its position within the code when first used in a label statement (INDENTIFIER :) within the code. Once given an actual address, using it in a label statement causes the label to indicate the address of the next line of code.

This command can appear anywhere in the script.

FULLACCESS( ADDRESS, SIZE )

Modifies the protection of addresses in the range from ADDRESS to (ADDRESS + SIZE - 1) inclusively to provide full access. If code can not be modified, this is used to enable it to be modified.
Any valid expression may be used for SIZE and ADDRESS. The address is treated as a hexadecimal number by default, so the 0x prefix and h postfix are optional.

This command can appear anywhere in the script.

ALLOC( IDENTIFIER, SIZE )

Allocates a minimum of SIZE bytes and creates a new label with the address of the allocated bytes. The label can be used the same as with labels declared with LABEL, however it is given an initial value, and therefor when it appears in a label statement (IDENTIFIER :) it indicates that the next line of code begins at that address.
Any valid expression may be used for SIZE.

This command can appear anywhere in the script.

DEALLOC( IDENTIFIER )

Indicates that the specified IDENTIFIER will be deallocated when MHS detaches from the target pocess.

IDENTIFIER must be a label, typically declared with ALLOC.

This command can appear anywhere in the script.

INCLUDE( FILEPATH )

Causes the Auto-Assembler to parse the specified file. Files may only be included to a recursion level of 1.

This command must appear at the location where the file’s script is to be inserted into the current script.

GLOBALALLOC( IDENITIFIER, SIZE)

Allocates IDENTIFIER exactly once, no matter how many times it is called on the same identifier. If IDENTIFIER already exists as a global, its current value is returned, otherwise SIZE bytes are allocated and the address of the allocation is returned and the indentifier is registered as a global so that subsequent attempts to globally allocate it will return the same address.

If the global already exists, its reference count is increased. These are only deallocated when the reference count is 0 and the reference count can only be decreased by GLOBALFREE and GLOBALDEALLOCATE.

When a symbol is registered as a global it is accessible by other Auto-Assemble scripts.

GLOBALFREE( IDENTIFIER )

Decreases the reference count on a global. If the count reaches 0 it is then freed from the target process and removed from the global list.

As with DEALLOC, this only deallocates memory when MHS detaches from the target process.

GLOBALDEALLOC( IDENTIFIER )

Same as GLOBALFREE.

REGISTERSYMBOL( IDENTIFIER )

Registers an already-allocated (via ALLOC) symbol (IDENTIFIER) as a global that can be accessed from other Auto-Assemble scripts.

UNREGISTERSYMBOL( IDENTIFIER )

Removes a previously registered global from the global list making it inaccessible via future Auto-Assemble scripts unless registered again later. If the symbol being undergistered was created via GLOBALALLOC then this behaves the same way as GLOBALFREE.

 

Writing Code

Code is written in standard ASM format. Each statement must be on one line. Comments are created with either ; or // and last until the end of the line. Comments can be extended to the next line by placing a \ at the end of the current line inside the comment. All standard 80x86, protected, FPU, MMX and 3DNow! instructions (including Athlon extensions to the MMX command set) are recognized. 16-bit addressing modes are not supported.

Labels are used to indicate the addresses of instructions and end with a colon. Labels can be pure numeric literals (for example 01005224 :), numeric expressions (for example gamex86.dll+5224h), or identifiers created with the LABEL, GLOBALALLOC, or ALLOC commands (for example MyLabel :). Labels created with LABEL do not have addresses assigned to them. Instead, they are used to obtain the address of the next instruction (or data). Therefore, to specify an address for code, a numeric label or a label created with ALLOC must be used. If the first label in the code was created with LABEL, the code will be compiled at address 0x00000000 and is guaranteed to fail injection.

DB, DW, DD, and DQ can be used to indicate data to apply in-place in the code. The data to be used must follow the command, and multiple values may be used per command. For example, db "Hello" 0 and db Ah 0xA 10 "hello\0" are valid. Each value can be any valid numeric, a string literal ("Cafebabe"), a Unicode string literal (L"Cafebabe"), or a label.
DB is used to create data composed of bytes. DW creates data composed of words (2 bytes). DD creates data composed of double-words (4 bytes), and DQ creates data composed of quad-words (8 bytes).

You can create floats by using DB (4-byte floats) and DQ (8-byte floats) and supplying floating-point numbers.
For example, dd 1.0f creates a 4-byte floating-point numeric equal to 1. Use periods to create floating-point numbers.

The following example shows how to place a DWORD into the middle of the code and then to access it.
Label( MyVal )
Label( AfterMyVal )
gamex86.dll+0x2EFC0 :
XOR EAX, EAX
JMP AfterMyVal
MyVal :

DD 0
AfterMyVal :
MOV EAX, [MyVal] ; Load our value into EAX.

This would create final code similar to the following:
0102EFC0: XOR EAX, EAX
0102EFC2: JMP 0102EFCB
0102EFC7: 00 00 00 00
0102EFCB: MOV EAX, DWORD PTR DS:[102EFC7]

Strings and Unicode strings use escape sequences to support miscellaneous characters. Therefore all of the following are valid and equal:
db "Hello" 0
db "Hello\0"
db 'H' "ello" 0h

Strings and Unicode strings are always evaluated to byte and word arrays respectively, regardless of in which command they appear.

 

Injecting

Press the Next button to preview the current code before injection.

Here you can examine the finalized code and copy the text from any of the edit controls to paste into other applications.

You can inject the code into the target process by pressing Inject. If you would like to make more modifications, or you only wanted to copy some of the text, press Back to return to the Auto-Assembler dialog.

After injecting, the Auto-Assembler dialog is shown again, allowing you to continue editing from the previous code base.

 

Opening and Saving

The File/Open menu item allows you to open existing Auto-Assembler scripts. Supported formats are .LSAA (L. Spiro Auto-Assemble) and .CEA (Cheat Engine Auto-Assemble). MHS’s Auto-Assembler provides approximately 80% compatibility with .CEA files and the compatibility will increase with future releases.

The File/Save and File/Save As menu items allow saving the current Auto-Assembler script.

Copyright © 2006 Shawn (L. Spiro) Wilcoxen