Auto Assembler Template Engine ("compiled templates")

Upload *YOUR* gamehacking tools/helpers here
Post Reply
ShyTwig16
Expert Cheater
Expert Cheater
Posts: 335
Joined: Thu Apr 06, 2017 7:14 pm
Reputation: 19

Auto Assembler Template Engine ("compiled templates")

Post by ShyTwig16 »

Auto Assembler Template Engine ("compiled templates")

For Lua Script Templates see this post.

This is an auto assembler template engine that compiles/renders templates, the template engine is based off [Link]. You can access variables and run lua code in the templates using the appropriate tags. There are two file's you'll need to start; "TemplateEngine.lua" and "AutoAssemblerTemplates.lua". You can just stick them both in the "autorun" folder. And you'll need to create the "Templates\cea" Folder (in the "autorun" folder) for the templates. It uses "registerAutoAssemblerTemplate" when loading so they will be in the same menu as the standard CE auto assembler templates.

When CE loads, "AutoAssemblerTemplates" will scan the templates folder for "LoadOrder.lua" if found and it returns a table/array of file names it will load in that order; if not found is will scan the templates folder for any ".CEA" files. When it finds a template file it will also look for "[template file name].settings.lua", the settings file is not required but allows for more control of the template and menu items added to the auto assembler form. The settings file can return a table of the template's settings, but this is not required (more on why later).

For simple output you can use "<<" and ">>" tags, what ever is returned will be converted to string if not already and replace where the open and close tags are; these can be a called function, variable, or just a string/number. For lua code you can use "<%" and "%>" tags, these can be full lua code; thus you can set/create variables, use loops, and if statements.

Here is an archive with the needed files and one example template and setting file.



Using a template file named "My basic template.CEA" like this:

Code: Select all

// Cheat Engine Version: << getCEVersion() >>
<% print('This will print when rendered but will not render in the template.') %>
//------------------------------ ENABLE ------------------------------
[ENABLE]
<% local text = 'here is a local variable created in the template.' %>
<< text >> So that's pretty cool.

// if you need "\<<" or "\<%" to be in the rendered template then you need to escape them.
// A single "<" doesn't need to be escaped, nor do ">>" and "%>".
{$lua}
print('This is in the template and not processed when rendered.')
{$asm}
//------------------------------ DISABLE ------------------------------
[DISABLE]
It will show up in the auto assembler form's template menu as "My basic template" and render like this:

Code: Select all

// Cheat Engine Version: 7.2

//------------------------------ ENABLE ------------------------------
[ENABLE]

here is a local variable created in the template. So that's pretty cool.

// if you need "<<" or "<%" to be in the rendered template then you need to escape them.
// A single "<" doesn't need to be escaped, nor do ">>" and "%>".
{$lua}
print('This is in the template and not processed when rendered.')
{$asm}
//------------------------------ DISABLE ------------------------------
[DISABLE]

There is another special file named "Header.CEA" which is rendered then passed to the template as "Header":

Code: Select all

<< Header >>
// This allows for a common header without polluting the template file it self 
// and can have lua code like the template files.
// But it will be a blank line if there's no header file.

For a settings file for "My basic template.CEA" we can create a file named "My basic template.settings.lua" like this:

Code: Select all

local settings = {
	Caption = 'Custom: Basic Template', 
	Shortcut = 'Ctrl+Alt+1', 
}
return settings
Template settings are listed here:

Code: Select all

Template Settings:
	Caption : string
		The caption of the template's menu item.
	Shortcut : string
		The shortcut of the template's menu item.
	AskForInjectionAddress : boolean
		Will prompt for a different address than the selected memory view lines if set to true.
		Allows the injection point to be offset from the AOB.
	AskForHookName : boolean
		Will prompt for a hook name if set to true.
	InjectionInfoLinesCount : number
		Will override the default number of lines in the "InjectionInfo" table.
	AppendToHookName : string
		Will be appended to the hook name if not already (if "AskForHookName" is true).
	WildCard : string/char
		Will override the default wild card if set.
The variables passed to the template, and settings file on final compilation, are listed here:

Code: Select all

Template Variables:
	Address : number
		The address of the injection point.
	AddressString : string
		The address of the injection point as a string. It will be in "module+offset" or hex format.
	AobAddress : number
		The address of the AOB start (first selected line in the memory view form).
	AobAddressString : string
		Same as address but for "AobAddress".
	OriginalBytes : table/array : number
		A table of numbers (base 10) of the original bytes.
	OriginalBytesString : string
		A string of the original bytes in a "XX XX" (base 16) format.
	ModuleName : string
		A string of the module name if the injection point and full AOB is in a module.
	Signature : string
		The AOB in a signature format, for now it just removes hard coded address and 4 byte offsets.
	AOB : table/array : number
		A table of numbers (base 10) of the raw AOB.
	AobOffset : number
		The difference between "AobAddress" and "Address" or nil if they are the same.
	AobOffsetString : string
		The AOB offset in hex format with the appropriate sign (e.g.: "+10" or "-10").
		Or nil if there is no aob offset.
	PointerDefault : string
		Either "dd 0" or "dq 0" based on if the target is 64 bit.
	BaseAddressRegistry : string
		If opcode in the format of "[reg+n]" is found this would be set to "reg".
	OriginalOpcode : table/array : string
		A table of strings of the original opcode lines.
	InjectionInfo : table/array : string
		Disassembler lines before and after the injection point.
	NopBytes : table
		A table of numbers (base 10) of the nop bytes (i.e.: 0x90) for the injection point 
		if it's not equal to 5 bytes. It will be an empty table if no nops are needed.
	NopBytesString : string
		The string of the nop bytes in a "XX XX" (base 16) format.
	CEVersion : number
		The current CE version.
	Date : string
		The current date.
	HookName : string
		If the template settings has "AskForHookName" set to true it will prompt for a hook name.
		Then title case the string (e.g.: "some test hook" will be come "Some Test Hook"), 
		and set this to that.
	HookNameParsed : string
		If the template settings has "AskForHookName" set to true it will prompt for a hook name.
		Then title case and remove spaces in the string 
		(e.g.: "some test hook" will be come "SomeTestHook"), and set this to that.
	FinalCompilation : boolean
		Only for the settings files as they get loaded once when CE loads then again at the start 
		of template rendering to get the template settings, and again just before rendering the 
		template but only on the last load will the environment be setup. 
		So this is used to know if the environment is setup if more environment setup is done in 
		the setting file.
Globals are accessible in the templates and settings files, but through a metatable thus they can not be set in a template or setting's file. But the environment variables can be manipulated in the settings file's directly during final compilation.

So say you don't like the signature that is generated and you just want to have a string of all the AOB bytes, but you don't want to do this in the template. You can use a settings file like this:

Code: Select all

if FinalCompilation then
	local bs = ''
	for _, b in ipairs(AOB) do
		bs = bs..string.format('%02X ', b)
	end
	Signature = bs
end
The template will get the new signature when rendered. And any "globals" (not really globals and only exist in the template/settings environment) created in the settings file is passed to the template file.


Full Examples:
Example 1
So if "GameTile", "GameFileVersion", and "GameVersion" globals aren't set; and you have a "Header.CEA" file like this:

Code: Select all

{
	Process				: << process >>  -  << targetIs64Bit() and 'x64' or 'x32' >>
	Module				: << ModuleName >>
	Game Title			: << GameTitle >>
	Game File Version 	: << GameFileVersion >>
	Game Version		: << GameVersion >>
	CE Version			: << CEVersion >>
	Script Version		: 1.0.1
	Date				: << Date >>
	Author				: ShyTwig16
	Name				: << HookNameParsed >>

	<< HookName >>
}
And a setting file like this (named "AobGetOpcodeAddress.settings.lua"):

Code: Select all

if FinalCompilation then
	local instLenght = getInstructionSize(Address)
	OpcodeAddressOffset = instLenght - 4
end

local settings = {
	Caption = 'Custom: AOB Get Opcode Address', 
	Shortcut = 'Ctrl+Alt+8', 
	AskForInjectionAddress = true, 
	AskForHookName = true, 
	AppendToHookName = 'hook', 
}
return settings
And a template file like this (named "AobGetOpcodeAddress.CEA"):

Code: Select all

<< Header >>
{$STRICT}
define(address, << AddressString >>)
define(bytes, << OriginalBytesString >>)

////
//// ------------------------------ ENABLE ------------------------------
[ENABLE]<% if ModuleName then %>
aobScanModule(aob<< HookNameParsed >>, << ModuleName >>, << Signature >>)<% else %>
aobScan(aob<< HookNameParsed >>, << Signature >>)<% end %><% if AobOffsetString then %>
define(inst<< HookNameParsed >>, aob<< HookNameParsed >><< AobOffsetString >>)<% else %>
define(inst<< HookNameParsed >>, aob<< HookNameParsed >>)<% end %>

getOpcodeAddress(ptr<< HookNameParsed >>, inst<< HookNameParsed >>+<< OpcodeAddressOffset >>)
registerSymbol(ptr<< HookNameParsed >>)


////
//// ------------------------------ DISABLE ------------------------------
[DISABLE]
unregisterSymbol(inst<< HookNameParsed >>)
unregisterSymbol(ptr<< HookNameParsed >>)
{<% if ModuleName then %>
Module: << ModuleName >>
<% end %>Address: << AddressString >>
AOB Address: << AobAddressString >><% for i, line in ipairs(InjectionInfo) do %>
<< line >><% end %>
}
And you select these lines in the memory view form (CE x64 tutorial step 2):

Code: Select all

Tutorial-x86_64.exe+2B3A9 - 81 BB F0070000 E8030000 - cmp [rbx+000007F0],000003E8 { 1000 }
Tutorial-x86_64.exe+2B3B3 - 75 33                 - jne Tutorial-x86_64.exe+2B3E8
Tutorial-x86_64.exe+2B3B5 - 48 8B 8B C0070000     - mov rcx,[rbx+000007C0]
Tutorial-x86_64.exe+2B3BC - B2 01                 - mov dl,01 { 1 }
And open the auto assembler form ("Ctrl+A"), and select the "Custom: AOB Get Opcode Address" menu item or press "Ctrl+Alt+8". When prompted for the injection address hit enter (keep first selected line) then when prompted for a hook name you enter "tutorial step 2". You'll get a rendered template like this:

Code: Select all

{
	Process				: Tutorial-x86_64.exe  -  x64
	Module				: Tutorial-x86_64.exe
	Game Title			: 
	Game File Version 	: 
	Game Version		: 
	CE Version			: 7.2
	Script Version		: 1.0.1
	Date				: 12/21/21
	Author				: ShyTwig16
	Name				: TutorialStep2Hook

	Tutorial Step 2 Hook
}
{$STRICT}
define(address, Tutorial-x86_64.exe+2B3A9)
define(bytes, 81 BB F0 07 00 00 E8 03 00 00)

////
//// ------------------------------ ENABLE ------------------------------
[ENABLE]
aobScanModule(aobTutorialStep2Hook, Tutorial-x86_64.exe, 81BBF0070000xxxxxxxx7533488B8BxxxxxxxxB201)
define(instTutorialStep2Hook, aobTutorialStep2Hook)

getOpcodeAddress(ptrTutorialStep2Hook, instTutorialStep2Hook+6)
registerSymbol(ptrTutorialStep2Hook)


////
//// ------------------------------ DISABLE ------------------------------
[DISABLE]
unregisterSymbol(instTutorialStep2Hook)
unregisterSymbol(ptrTutorialStep2Hook)
{
Module: Tutorial-x86_64.exe
Address: Tutorial-x86_64.exe+2B3A9
AOB Address: Tutorial-x86_64.exe+2B3A9
Tutorial-x86_64.exe+2B392 - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B394 - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B396 - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B398 - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B39A - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B39C - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B39E - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B3A0 - 53                - push rbx
Tutorial-x86_64.exe+2B3A1 - 48 8D 64 24 E0    - lea rsp,[rsp-20]
Tutorial-x86_64.exe+2B3A6 - 48 89 CB          - mov rbx,rcx
Tutorial-x86_64.exe+2B3A9 - 81 BB F0070000 E8030000- cmp [rbx+000007F0],000003E8   <<<---- Injection point
Tutorial-x86_64.exe+2B3B3 - 75 33             - jne Tutorial-x86_64.exe+2B3E8
Tutorial-x86_64.exe+2B3B5 - 48 8B 8B C0070000 - mov rcx,[rbx+000007C0]
Tutorial-x86_64.exe+2B3BC - B2 01             - mov dl,01
Tutorial-x86_64.exe+2B3BE - 48 8B 83 C0070000 - mov rax,[rbx+000007C0]
Tutorial-x86_64.exe+2B3C5 - 48 8B 00          - mov rax,[rax]
Tutorial-x86_64.exe+2B3C8 - FF 90 40040000    - call qword ptr [rax+00000440]
Tutorial-x86_64.exe+2B3CE - 48 8B 8B E0070000 - mov rcx,[rbx+000007E0]
Tutorial-x86_64.exe+2B3D5 - 30 D2             - xor dl,dl
Tutorial-x86_64.exe+2B3D7 - 48 8B 83 E0070000 - mov rax,[rbx+000007E0]
Tutorial-x86_64.exe+2B3DE - 48 8B 00          - mov rax,[rax]
}
Example 2
With the same header file as example 1.

And a setting file like this (named "AobFullInjection.settings.lua"):

Code: Select all

local settings = {
	Caption = 'Custom: AOB Full Injection', 
	Shortcut = 'Ctrl+Alt+6', 
	AskForInjectionAddress = true, 
	AskForHookName = true, 
	AppendToHookName = 'hook', 
}
return settings
And a template file like this (named "AobFullInjection.CEA"):

Code: Select all

<< Header >>
{$STRICT}
define(address, << AddressString >>)
define(bytes, << OriginalBytesString >>)

////
//// ------------------------------ ENABLE ------------------------------
[ENABLE]<% if ModuleName then %>
aobScanModule(aob<< HookNameParsed >>, << ModuleName >>, << Signature >>)<% else %>
aobScan(aob<< HookNameParsed >>, << Signature >>)<% end %><% if AobOffsetString then %>
define(inj<< HookNameParsed >>, aob<< HookNameParsed >><< AobOffsetString >>)<% else %>
define(inj<< HookNameParsed >>, aob<< HookNameParsed >>)<% end %>

assert(inj<< HookNameParsed >>, bytes)
registerSymbol(inj<< HookNameParsed >>)

alloc(mem<< HookNameParsed >>, 0x400, inj<< HookNameParsed >>)

label(ptr<< HookNameParsed >>)
registerSymbol(ptr<< HookNameParsed >>)

label(n_code)
label(o_code)
label(exit)
label(return)

mem<< HookNameParsed >>:
	ptr<< HookNameParsed >>:
		<< PointerDefault >>
	align 10 CC
	n_code:
		mov [ptr<< HookNameParsed >>],<< BaseAddressRegistry >>
	o_code:<% for i, line in ipairs(OriginalOpcode) do %>
		<< line >><% end %>
	exit:
		jmp return


////
//// ---------- Injection Point ----------
inj<< HookNameParsed >>:
	jmp n_code<% for _, _ in ipairs(NopBytes) do %>
		nop<% end %>
	return:


////
//// ------------------------------ DISABLE ------------------------------
[DISABLE]
////
//// ---------- Injection Point ----------
inj<< HookNameParsed >>:
	db bytes

unregisterSymbol(inj<< HookNameParsed >>)

unregisterSymbol(ptr<< HookNameParsed >>)

dealloc(mem<< HookNameParsed >>)
{<% if ModuleName then %>
Module: << ModuleName >>
<% end %>Address: << AddressString >>
AOB Address: << AobAddressString >><% for i, line in ipairs(InjectionInfo) do %>
<< line >><% end %>
}
And you select these lines in the memory view form (CE x64 tutorial step 2):

Code: Select all

Tutorial-x86_64.exe+2B3A6 - 48 89 CB              - mov rbx,rcx
Tutorial-x86_64.exe+2B3A9 - 81 BB F0070000 E8030000 - cmp [rbx+000007F0],000003E8 { 1000 }
Tutorial-x86_64.exe+2B3B3 - 75 33                 - jne Tutorial-x86_64.exe+2B3E8
Tutorial-x86_64.exe+2B3B5 - 48 8B 8B C0070000     - mov rcx,[rbx+000007C0]
Tutorial-x86_64.exe+2B3BC - B2 01                 - mov dl,01 { 1 }
And open the auto assembler form ("Ctrl+A"), and select the "Custom: AOB Full Injection" menu item or press "Ctrl+Alt+6". When prompted for the injection address you enter this address "Tutorial-x86_64.exe+2B3A9" then when prompted for a hook name you enter "tutorial step 2". You'll get a rendered template like this:

Code: Select all

{
	Process				: Tutorial-x86_64.exe  -  x64
	Module				: Tutorial-x86_64.exe
	Game Title			: 
	Game File Version 	: 
	Game Version		: 
	CE Version			: 7.2
	Script Version		: 1.0.1
	Date				: 12/21/21
	Author				: ShyTwig16
	Name				: TutorialStep2Hook

	Tutorial Step 2 Hook
}
{$STRICT}
define(address, Tutorial-x86_64.exe+2B3A9)
define(bytes, 81 BB F0 07 00 00 E8 03 00 00)

////
//// ------------------------------ ENABLE ------------------------------
[ENABLE]
aobScanModule(aobTutorialStep2Hook, Tutorial-x86_64.exe, 4889CB81BBF0070000xxxxxxxx7533488B8BxxxxxxxxB201)
define(injTutorialStep2Hook, aobTutorialStep2Hook+3)

assert(injTutorialStep2Hook, bytes)
registerSymbol(injTutorialStep2Hook)

alloc(memTutorialStep2Hook, 0x400, injTutorialStep2Hook)

label(ptrTutorialStep2Hook)
registerSymbol(ptrTutorialStep2Hook)

label(n_code)
label(o_code)
label(exit)
label(return)

memTutorialStep2Hook:
	ptrTutorialStep2Hook:
		dq 0
	align 10 CC
	n_code:
		mov [ptrTutorialStep2Hook],rbx
	o_code:
		cmp [rbx+000007F0],000003E8
	exit:
		jmp return


////
//// ---------- Injection Point ----------
injTutorialStep2Hook:
	jmp n_code
		nop
		nop
		nop
		nop
		nop
	return:


////
//// ------------------------------ DISABLE ------------------------------
[DISABLE]
////
//// ---------- Injection Point ----------
injTutorialStep2Hook:
	db bytes

unregisterSymbol(injTutorialStep2Hook)

unregisterSymbol(ptrTutorialStep2Hook)

dealloc(memTutorialStep2Hook)
{
Module: Tutorial-x86_64.exe
Address: Tutorial-x86_64.exe+2B3A9
AOB Address: Tutorial-x86_64.exe+2B3A6
Tutorial-x86_64.exe+2B392 - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B394 - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B396 - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B398 - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B39A - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B39C - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B39E - 00 00             - add [rax],al
Tutorial-x86_64.exe+2B3A0 - 53                - push rbx
Tutorial-x86_64.exe+2B3A1 - 48 8D 64 24 E0    - lea rsp,[rsp-20]
Tutorial-x86_64.exe+2B3A6 - 48 89 CB          - mov rbx,rcx   <<<---- AOB
Tutorial-x86_64.exe+2B3A9 - 81 BB F0070000 E8030000- cmp [rbx+000007F0],000003E8   <<<---- Injection point
Tutorial-x86_64.exe+2B3B3 - 75 33             - jne Tutorial-x86_64.exe+2B3E8
Tutorial-x86_64.exe+2B3B5 - 48 8B 8B C0070000 - mov rcx,[rbx+000007C0]
Tutorial-x86_64.exe+2B3BC - B2 01             - mov dl,01
Tutorial-x86_64.exe+2B3BE - 48 8B 83 C0070000 - mov rax,[rbx+000007C0]
Tutorial-x86_64.exe+2B3C5 - 48 8B 00          - mov rax,[rax]
Tutorial-x86_64.exe+2B3C8 - FF 90 40040000    - call qword ptr [rax+00000440]
Tutorial-x86_64.exe+2B3CE - 48 8B 8B E0070000 - mov rcx,[rbx+000007E0]
Tutorial-x86_64.exe+2B3D5 - 30 D2             - xor dl,dl
Tutorial-x86_64.exe+2B3D7 - 48 8B 83 E0070000 - mov rax,[rbx+000007E0]
Tutorial-x86_64.exe+2B3DE - 48 8B 00          - mov rax,[rax]
}

Post Reply

Who is online

Users browsing this forum: No registered users