Skip to content

Scripted API

Neo edited this page Feb 21, 2022 · 15 revisions

Scripted API

This page explains the various objects, functions and values that get added into the JS engine via QJS scripts (present in Support folder).

Table of Contents


Constants

Technically speaking these are not 'constants', since it is possible to overwrite them.

However, you should avoid doing that, as other scripts would be relying on these.

Strings

Name Description
YMLFILTER Filter string for YAML files. Used with user inputs of D_InFile type.

Error objects

These are ready made standard JS Error objects (currently only used by extensions).

Name Message Description
NO_EXE No Valid Exe loaded Used when the Exe.FileSize is 0. i.e. no file has been loaded properly yet.
Primarily used in extensions.
NO_OUTPUT Unable to generate output file Used when the Open function of a TextFile or a BinFile object fails to open in write mode.
Primarily used in extensions.

Hex patterns

The hex search functions of Exe object supports the usage of wildcard patterns using (? , [, ] and .).

But writing the same patterns again and again can become quite tedious. So you can use the following 'constants' for them instead.

Name Value Description
WC ?? 1 byte Wild Card.
WCp [0.......] 1 byte Wild Card with positive sign bit.
WCn [1.......] 1 byte Wild Card with negative sign bit.
ALLWC ?? ?? ?? ?? 4 byte value, all Wild Cards.
ALLWCp ?? ?? ?? [0.......] 4 byte value, all Wild Cards & positive sign bit.
ALLWCn ?? ?? ?? [1.......] 4 byte value, all Wild Cards & negative sign bit.
ALL00 00 00 00 00 Equal to 0.
POS1WC ?? 00 00 00 4 byte positive value, with 1 LSB as wildcard.
POS2WC ?? ?? 00 00 4 byte positive value, with 2 LSB as wildcard.
POS3WC ?? ?? ?? 00 4 byte positive value, with 3 LSB as wildcard.
POS4WC ?? ?? ?? 0? 4 byte positive value, with 3 LSB and lower half of the MSB as wildcard.
ALLFF FF FF FF FF Equal to -1.
NEG1WC ?? FF FF FF 4 byte negative value, with 1 LSB as wildcard.
NEG2WC ?? ?? FF FF 4 byte negative value, with 2 LSB as wildcard.
NEG3WC ?? ?? ?? FF 4 byte negative value, with 3 LSB as wildcard.
NEG4WC ?? ?? ?? F? 4 byte negative value, with 3 LSB and lower half of the MSB as wildcard.

Common instructions

These are some frequently encountered/used instructions found across scripts.

Name Description
PUSH_0 the hex code for push 0
PUSH_1 the hex code for push 1
PUSH_2 the hex code for push 2
PUSH_R the hex code for push <reg32>
PUSH_EAX the hex code for push eax
POP_R the hex code for pop <reg32>
POP_EAX the hex code for pop eax
FP_START the hex code combination of push ebp followed by mov ebp, esp which sets up the Frame Pointer.
FP_STOP the hex code combination of mov esp, ebp followed by pop ebp which restores the stack and releases the Frame Pointer (for that function)

Misc items

  • OpCodeList Mapping of various opcodes. Used internally by Instr class.

  • OpTypes Collection of Operand types. It has the following keys. Used by Instr class & Instruction Generators

    Key Description
    OpTypes.ERR Illegal operation
    OpTypes.A Acc <, Imm>
    OpTypes.R Reg <, Imm>
    OpTypes.I <Imm>
    OpTypes.R_R Reg, Reg <, Imm>
    OpTypes.D_A Ptr [Disp], Acc <, Imm>
    OpTypes.P_R Ptr [...], Reg <, Imm>
    OpTypes.A_D Acc, Ptr [Disp] <, Imm>
    OpTypes.R_P Reg, Ptr [...] <, Imm>

    Legend

    • Imm = Immediate value (Number or Hex) which is optional and depends on the instruction whether they will be present or not.
    • Reg = Any Register object.
    • Acc = Any primary Register object. For general purpose registers this would be the Accumulator (hence the name).
    • Ptr [...] = Memory Pointer which takes the generic form [scale*reg + reg + displacement], all parts of which are optional, but atleast 1 should be there.
    • Ptr [Disp] = Memory Pointer with only Displacement.

Classes

The following classes are available from the support scripts.

Name Description
Register Represents various CPU registers.
PtrSize Represents data size of Memory Pointers.
IPrefix Represents instruction prefixes.
ModRM Represents a Mod R/M byte.
SIBase Represents a SIB byte.
Instr Represents a CPU instruction itself.
OpData Internal class used for parsing instruction arguments.
Only used by Instruction Generators.
RsrcEntry Represents a Resource Directory Entry in the Exe.
Only used by 1 patch as of now hence not going into details.

Refer the respective links for more details on each class.


Special Functions

PatchReporter

Called directly from the tool when it needs to report changes made by a patch.

This is just an FYI. Do not call this function directly.

Testers

These functions test the type of the value provided or check if it's within certain limits.

IsNum

Checks whether the specified value is a number.

Syntax:

IsNum(value)

Returns: true or false


IsStr

Checks whether the specified value is a string.

Syntax:

IsStr(value)

Returns: true or false


IsBool

Checks whether the specified value is a boolean.

Syntax:

IsBool(value)

Returns: true or false


IsArr

Checks whether the specified value is an array.

Syntax:

IsArr(value)

Returns: true or false


IsNumOrStr

Checks whether the specified value is either a number or a string

Syntax:

IsNum(value)

Returns: true or false


IsWord

Checks whether the specified value is composed of 2 bytes. The value can be a number or hex string.

Syntax:

IsWord(value, [signed])
Argument Description
value The value to be tested
signed Optional boolean indicating whether value provided is signed number or not. Default is true

Returns: true or false

IsByte

Checks whether the specified value is composed of 1 byte. The value can be a number or hex string.

Syntax:

IsByte(value, [signed])
Argument Description
**value ** The value to be tested
signed Optional boolean indicating whether value provided is signed number or not. Default is true

Returns: true or false


Placeholder functions

While writing QJS scripts, you often need to use a placeholder for values known later.

For this we make use of filler patterns. These functions deal with the generation & substitution of these patterns.

Filler

Generates the filler pattern to be used in code.

Syntax:

Filler(idx, [bc])
Argument Description
idx Index to be used for generating the filler
bc Optional byte count to be used in the pattern. Default is 4 bytes.

Returns: the generated pattern


SwapFillers

Substitutes the filler(s) specified with corresponding replacement value(s) in the provided hex string and returns the updated one.

An array of hex strings can also be provided (which will get concatenated).

Please note that the modification is not done in-place, so the output of the function need to be saved.

Syntax:

SwapFillers(hexstr, map)
SwapFillers(hexstr, count, map)
Argument Description
hexstr Either a complete hex string or array of hex strings in which the swap needs to be done.
count Optional no of occurences of all the fillers to be swapped.
If omitted or negative, all occurences will get swapped.
map A hash map of the form <idx>: <repl> where
idx = The filler pattern specification. It is either the index number OR string of the form 'index, bc'
repl = replacement value. It can be a number OR a hex string OR an array of these. If it is an array then each succeeding match uses corresponding element.

For e.g. if we consider the following script

let code = PUSH(Filler(1)) + MOV(EAX, ECX) + PUSH(Filler(2,1))
code = SwapFillers(code, 1, {1: 0x100, '2,1': 0x40});

This is equivalent to

let code = PUSH(0x100) + MOV(EAX, ECX) + PUSH(0x40);

*Returns: the updated string. *


SetFillTargets

Substitutes the filler(s) specified with delta values in the provided hex string and returns the updated one.

An array of hex strings can also be provided (which will get concatenated).

The delta values are calculated based on the target addresses specified for each filler pattern and serves to transfer control as part of a jump or call.

Syntax:

SetFillTargets(hexstr, map)
SetFillTargets(hexstr, count, map)
Argument Description
hexstr Either a complete hex string or array of hex strings in which the swap needs to be done.
count Optional no of occurences of all the fillers to be swapped.
If omitted or negative, all occurences will get swapped.
map A hash map containing start: <source> followed by key-value pairs of the form <idx>: <target> where
source = Address of the first byte
idx = The filler pattern specification. It is either the index number OR string of the form 'index, bc'
target = The target address.

For e.g. we can use it like this.

let code = CALL(Filler(1)) + MOV(ECX, EAX) + JMP(Filler(2,1))
code = SetFillTargets(code, {
	start: 0x404100,
	    1: 0xA12100,
	'2,1': 0x404120,
});

*Returns: the updated string. *


Converters

These functions convert one type of data to another.

Wrap

It wraps up the specified value into an array unless the value itself is an array and return the result.

Syntax:

Wrap(value)

Returns: the resulting array or an empty array if the value is undefined.


Calculators

BitWidth

Calculates the bit width of the specified value which can be a number, string or Register object.

Syntax:

BitWidth(value)

Returns: the calculated width


Distance

Calculates the distance between the given two values and return it. If they are not numbers then the target itself is returned.

Syntax:

Distance(target, source
Argument Description
target The target value (usually an address). Can be either number or hex string.
source The source value from where we need to calculate the distance.
If the target is a hex string this value is ignored.

Returns: the calculated distance


MapAddrs

Calculate the addresses for various indices in the array of hex strings (instructions) w.r.t. the starting address.

Syntax:

MapAddrs(start, parts)
Argument Description
start Starting address i.e. Address of the first byte.
parts The array of hex strings.

Returns: The array of offsets/addresses calculated.


Extractors

CaseAddr

Retrieve the switch jump address for the specified case.

Syntax:

CaseAddr(num, movzx, [reflect])
CaseAddr(num, movzx, jmpdp, [reflect])
CaseAddr(num, atype, movzx, [reflect])
CaseAddr(num, atype, movzx, jmpdp, [reflect])
Argument Description
num The case number whose address you want to retrieve.
atype Optional AddrType for the returned address. Default is PHYSICAL.
movzx The PHYSICAL address of the MOVZX DWORD PTR instruction pertaining to the switch case.
Can be set to null if a valid jmpdp address has been provided.
jmpdp Optional PHYSICAL address of the JMP DWORD PTR instruction pertaining to the switch case.
If omitted, then it is calculated from movzx.
reflect Optional boolean to 'reflect' existing changes done by patches. Default is false.

Returns: The extracted case address or -1 in case of failure.


FindInstr

Searches for a particular instruction using a testing function provided.

Syntax:

FindInstr(testFn, from, [to])
Argument Description
testFn The function to use for testing each instruction to find the one we want.
It should accept an Instr object as argument and return true or false.
The test can be anything from simple opcode comparison to more intricate checks.
from The address from where we need to begin the search
to Optional ending address to stop the search at.
If not provided then the search proceeds till the end of CODE or DIFF sections (based on where the from address is located).

Returns: The matching Instr object or null in case no match was found / invalid testFn or from address was specified.


GetInstr

Fetches the 'nth' instruction after the specified one.

Syntax:

GetInstr(from, n)
GetInstr(current, n)
Argument Description
from The address of the 'current' instruction after which we need to fetch.
current The 'current' instruction as an Instr object.
It should have been extracted with Instr.FromAddr function earlier.
n The number of the instruction to be fetched.
for e.g. if n = 2 then we get the second instruction after the specified one.

Returns: The extracted Instr object or null in case of failure.


GetImpRefs

Retrieves the references of an imported function.

Syntax:

GetImpRefs(funcName)
GetImpRefs(funcName, dllName)
GetImpRefs(funcName, dllName, ordinal)
Argument Description
funcName The imported function's name. If this is blank then the ordinal number should be specified.
dllName Optional name of the dll from which the function is getting imported.
ordinal Optional ordinal number. If funcName is empty, this need to be specified..

Returns: Map containing funcAddr and refAddrs


Combination Wrappers

These are functions wrapping a common combination of the aforementioned functions for ease of use.

AutoHook

Higher level wrapper used for inserting the provided code(s) and creating a JMP/CALL to it from a specific location in the Exe.

Extra arguments can be provided for processing the provided code before insertion

Syntax:

AutoHook(fromAddr, codes, argMap)
Argument Description
fromAddr The PHYSICAL address from where the JMP/CALL need to be made.
codes The template code(s) that need to be inserted
argMap A map of arguments that are used to process the codes provided to get the final code to be inserted.

The argMap supports the following keys, all of which are optional

Key Description
allocSize No. of bytes to be allocated for the code.
If not specified, bytecount of the codes provided is calculated and used.
snap Snap value to use with Exe.Allocate function.
Defaults to 0x10.
localVals Set of value(s), relative to the Allocated address for use in SwapFillers function.
localTgts Set of address(es), relative to the Allocated address for use in SetFillTargets function.
values Set of final value(s) to be used in SwapFillers function.
targets Set of target address(es) to be used in SetFillTargets function.
postProc Function pointer for any further post processing of the code after localVals, localTgts, values & targets have been applied.

It will get the following arguments.
- The processed code
- VIRTUAL allocated address
- procArgs
- This argument map
procThis Object to be used as the this pointer for the postProc function call
procArgs Arguments that would be provided as the third argument to postProc function call
isCall Boolean to indicate whether we should CALL this code or JMP to the finalized code
isPtr Boolean to indicate whether the JMP/CALL should be an indirect one (true) or direct (false).
nops No. of NOPs to be placed after the JMP/CALL
srcOffset Offset to be added to the fromAddr to place the JMP/CALL at.
jcOffset Offset to be added to the allocated address to get the target for the JMP/CALL.

Returns: The result of the Exe.Allocate call i.e. [ PHYSICAL address, VIRTUAL address, Size allocated ]


MultiAlloc

Higher level wrapper for allocating contiguous position in DIFF instead of seperate allocations for multiple variables.

Syntax:

MultiAlloc(size1, size2, ...)
Argument Description
size1 Size needed for variable no. 1
size2 Size needed for variable no. 2
....

Returns: The list of VIRTUAL addresses allocated in the same order as the sizes provided.


Logging

A set of functions have been provided (utilizing $ & _ signs) for logging messages into a seperate logfile.

You also have the option of simultaneously sending these messages to the Console OR the Output frame in Script Window/Results page.

Colloquially we are calling them Dollar functions.

Log object

To manage the messages sent to the Dollar functions a special Log object works in the background. It has 4 data members:

  • Tee

    This is a boolean which indicates whether the messages will be sent to Output frame.

  • Handle

    This is either undefined (no logging) or has a TextFile object pointing to the logfile in write mode.

  • Depth

    Indicates the active depth (call stack level) for logging.

  • UserDepth

    Indicates the user specified depth. Message will only be sent if this value >= Depth.


Rather than modifying these members directly, the following functions have been provided.

start

Enables writing to the log file.

Syntax:

Log.start([filename])
Argument Description
filename Optional filename to be used for the logfile.
If omitted then an automatic filename is used which takes the form Comment_Log_<ISOtime>.log

Returns: true if succesfully setup else false


stop

Stops writing to the log file.

Syntax:

Log.stop()

Returns: Log object itself


show

Only useful in Main GUI & Test Bench. It displays the currently active log file.

Syntax:

Log.show()

Returns: Log object itself if there was a logfile open else false*


cc

Enables/Disables mirroring of the messages to the Console OR the Output frame in Script Window/Results page.

Syntax:

Log.cc([state])
Argument Description
state Optional boolean serving as the new value for Log.Tee. If omitted, then Log.Tee becomes true

Returns: Log object itself


write

Writes a message to the log file, if logging has started.

Syntax:

Log.write(msg)
Argument Description
msg Message line to be written to file

Returns: Log object itself


dive

Increases the Depth by 1.

It also passes through any arguments it receives as a string after concatenation using ' :: '.

Syntax:

Log.dive(arg0, arg1, ...)

Returns: If arguments are provided then the concatenated result, otherwise Log object itself

rise

Counterpart to dive. Decreases the Depth by 1.

It also passes through the arguments it receives (as a list if multiple arguments are provided).

Syntax:

Log.rise(arg0, arg1, ...)

Returns: Either the arguments which were provided or the Log object itself

setDepth

Used for setting the UserDepth value.

Syntax:

Log.setDepth(d)

Returns: The Log object itself


valid

Compares UserDepth against active Depth and returns true if the former is higher or equal.

This is used by all the Dollar functions below while sending messages to the Output frame as well as the log file .

Syntax:

Log.valid()

Returns: true if UserDepth >= Depth


Dollar functions

As discussed above these functions are composed of $ and _ in their names and serve to send messages to a logfile and/or the Output frame.

At present there are 4 such functions available.

  1. $$(msg)

    This is the most basic version amongst the functions.

    It simply writes the message to the logfile (if enabled) and to the Output (if enabled).

    The msg will always be treated as a string.

    Returns: true if the function was called with a proper argument else false

  2. $$$(msg)

    This is a variation of $$ (the message string is always written to the Output irrespective of Log.Tee).

    Returns: true if the function was called with a proper argument else false

  3. $_

    This function is used for writing header strings (i.e. it is underlined and optionally bold) or for simple drawing a line.

    It has the following syntaxes.

    $_(msg, [chr])
    $_(msg, bold, [chr])
    $_(tee, msg, [chr])
    $_(tee, msg, bold, [chr])
    $_(len, [chr])
    $_(len, bold, [chr])
    $_(tee, len, [chr])
    $_(tee, len, bold, [chr])
    Argument Description
    tee Optional boolean override for Log.Tee
    len Optional length to use for the underline. If a msg has been provided then it's string length is used as len.
    bold Optional boolean to specify whether bold font need to be used in Output. Default is false.
    chr Optional character to use for constructing the underline. Default is +

    Returns: true if the function was called with a proper message OR line length else false

  4. _$_

    This is a variation of $_ with the line being drawn both above and under the message.

    Returns: true if the function was called with a proper message OR line length else false

Primary use case for these functions (atleast for me) is when they double up as comments.

For e.g. Instead of writing

/// Find the string 'Hello there'

I can write it as

let _ = patchName + " :"; //a prefix to show where the message originated from.

$$(_ + "Find the string 'Hello there'")

DumpFunc

Logs the complete hex code of a function from the Exe with each instruction on a separate line till RETN statement.

It makes use of the $$$ function internally.

Syntax:

DumpFunc(addr, [atype])
DumpFunc(name, addr, [atype])
Argument Description
name Optional string to use as the name.
If omitted, "UnknFunc" is shown as the name.
addr The address to start 'dumping' from.
atype Optional AddrType of the starting address specified.
If omitted, PHYSICAL` address is expected.

Debugging functions

All these functions display some specific items in the Console OR the Output frame of ScriptWindow / Results page (depending on which tool you have started up).

Info

Alias of console.info function for displaying generic messages.

Syntax:

Info(<msg1>, <msg2>, ...)

Debug

Alias of console.log function for displaying debug messages.

Syntax:

Debug(<msg1>, <msg2>, ...)

NewLine

Adds an empty line to the Output frame / Console.

Syntax:

NewLine()

ShowVar

Displays the provided variable's name and value. The variable need to be wrapped within { } .

If the value is an array, then it's elements will be displayed within [ ] identical to how ShowArr displays it.

Syntax:

ShowVar({varName})
ShowVar(prefix, {varName})
Argument Description
prefix Optional string to prefix before the variable name
varName The variable which needs to be displayed.
Ensure to wrap it in { } else it won't work.

ShowArr

Displays the elements in the provided array hierarchically taking the form:

<name> = [
	0 => <value0>
	1 => <value1>
	....
]

Syntax:

ShowArr(arr)
ShowArr(name, arr)
ShowArr(indent, arr)
ShowArr(indent, name, arr)
Argument Description
indent Optional no of tabspaces to prefix . Default is 0.
name Optional string to use as the name. If omitted, "Array" is shown as the name.
arr The array to be displayed.

Dump

Displays the constructor name as well as all the property names and values of an object.

Syntax:

Dump(obj)
Dump(name, obj)
Argument Description
name Optional name of the object. If omitted, only the constructor name is shown.
obj The object whose details need to be displayed.

ShowAddr

Displays the PHYSICAL & VIRTUAL counterparts of an address.

It will be displayed in the form:

<name> = <phyAddr> ( <virAddr> )

You can also wrap the variable containing the address within { } to display the name as well.

Syntax

ShowAddr(addr, [atype])
ShowAddr(name, addr, [atype])
ShowAddr({varName}, [atype])
Argument Description
name Optional string to use as the name. If omitted, "Addr" is shown.
addr The address to be displayed.
varName The variable containing the address to be displayed.
Ensure to wrap it in { } to use the variable's name.
atype Optional AddrType of the address provided. If omitted, PHYSICAL address is expected.

ShowAddrs

Displays the PHYSICAL & VIRTUAL counterparts of all the addresses in the provided list.

It will be displayed in the form:

<name> = [
	0 => <phyAddr0> ( <virAddr0> )
	1 => <phyAddr1> ( <virAddr1> )
	....
]

You can also wrap the variable containing the address list within { } to display the name as well.

Syntax

ShowAddrs(addrList, [atype])
ShowAddrs(name, addrList, [atype])
ShowAddrs({varName}, [atype])
Argument Description
name Optional string to use as the name. If omitted, "Addrs" is shown.
addrList The address list to be displayed.
varName The variable containing the address list to be displayed.
Ensure to wrap it in { } to use the variable's name.
atype Optional AddrType of the addresses provided. If omitted, PHYSICAL addresses are expected.

Counter functions

These functions are related to an internal counter. Initially it will be undefined.

ResetC

Resets the internal counter to 0.

Syntax:

ResetC()

Returns: true (just to avoid an undefined return)


IncrC

Increments the counter by 1

Syntax:

IncrC()

Returns: true (just to avoid an undefined return)


ShowC

Shows the current count along with the Exe.Version & Exe.BuildDate.

If the counter has not been defined yet with ResetC then the message Counter not set is displayed instead of the count.

Syntax:

ShowC();

Returns: true (just to avoid an undefined return)


Utilities

These are some utility functions not belonging to any of the earlier categories.

ParseData

Parses the data provided into a 4 part array.

Used internally by SIBase & ModRM classes, so not discussing any further.

Cancel

Throws a cancellation warning depending on the provided arguments. It has 3 different forms.

  1. Syntax:

    Cancel()

    With no argument, the tool simply shows a Cancelled warning.

  2. Syntax:

    Cancel(message)

    The tool will show a Cancelled - <message> warning.

  3. Syntax:

    Cancel(name, defVal)

    The tool will show a Cancelled - '<name>' reverted to <defVal> warning.

    The name will be shown with bold font and the defVal with bold italic.


UserChoice

A simple wrapper over Exe.GetUserInput function for D_Bool type to ask Yes/No questions without worrying about the variable.

Primarily used in extensions.

Syntax:

UserChoice(title, prompt)

MakeMap

Quick wrapper to create a Map object from it's arguments

Syntax:

MakeMap(key1, val1, key2, val2, ...)

Returns: the generated Mapobject


ReloadPatch

Wrapper script to reload an already selected patch. Mostly used in cleanup functions.

Syntax:

ReloadPatch(name, [funcName], [sendName])
Argument Description
name Name of the patch (not it's title).
funcName Optional name of the function to be called.
If not provided name itself is considered.
sendName Optional boolean value to indicate whether the name itself needs to be send as argument to the patch function.


Return to top


Further reading

Clone this wiki locally