-
-
Notifications
You must be signed in to change notification settings - Fork 53
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).
- Constants
- Classes
- Special functions
- Testers
- Placeholder functions
- Converters
- Calculators
- Extractors
- Combination Wrappers
- Logging
- Debugging functions
- Counter functions
- Overrides
- Instruction Generators
- Utilities
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.
Name | Description |
---|---|
YMLFILTER |
Filter string for YAML files. Used with user inputs of D_InFile type. |
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. |
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. |
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) |
-
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.
-
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.
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.
These functions test the type of the value provided or check if it's within certain limits.
Checks whether the specified value is a number.
Syntax:
IsNum(value)
Returns:
true
orfalse
Checks whether the specified value is a string.
Syntax:
IsStr(value)
Returns:
true
orfalse
Checks whether the specified value is a boolean.
Syntax:
IsBool(value)
Returns:
true
orfalse
Checks whether the specified value is an array.
Syntax:
IsArr(value)
Returns:
true
orfalse
Checks whether the specified value is either a number or a string
Syntax:
IsNum(value)
Returns:
true
orfalse
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
orfalse
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
orfalse
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.
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
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> whereidx = 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. *
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> wheresource = 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. *
These functions convert one type of data to another.
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
.
Calculates the bit width of the specified value which can be a number, string or Register object.
Syntax:
BitWidth(value)
Returns: the calculated width
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
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.
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.
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 / invalidtestFn
orfrom
address was specified.
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.
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
andrefAddrs
These are functions wrapping a common combination of the aforementioned functions for ease of use.
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 ]
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.
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.
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.
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 elsefalse
Stops writing to the log file.
Syntax:
Log.stop()
Returns:
Log
object itself
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 elsefalse
*
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
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
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
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
Used for setting the UserDepth
value.
Syntax:
Log.setDepth(d)
Returns: The
Log
object itself
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
ifUserDepth
>=Depth
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.
-
$$(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 elsefalse
-
$$$(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 elsefalse
-
$_
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 aslen
.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 elsefalse
-
_$_
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 elsefalse
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'")
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. |
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).
Alias of console.info
function for displaying generic messages.
Syntax:
Info(<msg1>, <msg2>, ...)
Alias of console.log
function for displaying debug messages.
Syntax:
Debug(<msg1>, <msg2>, ...)
Adds an empty line to the Output frame / Console.
Syntax:
NewLine()
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. |
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. |
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. |
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. |
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. |
These functions are related to an internal counter. Initially it will be undefined
.
Resets the internal counter to 0.
Syntax:
ResetC()
Returns:
true
(just to avoid anundefined
return)
Increments the counter by 1
Syntax:
IncrC()
Returns:
true
(just to avoid anundefined
return)
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 anundefined
return)
These are some utility functions not belonging to any of the earlier categories.
Parses the data provided into a 4 part array.
Used internally by SIBase & ModRM classes, so not discussing any further.
Throws a cancellation warning depending on the provided arguments. It has 3 different forms.
-
Syntax:
Cancel()
With no argument, the tool simply shows a
Cancelled
warning. -
Syntax:
Cancel(message)
The tool will show a
Cancelled - <message>
warning. -
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.
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)
Quick wrapper to create a Map
object from it's arguments
Syntax:
MakeMap(key1, val1, key2, val2, ...)
Returns: the generated
Map
object
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. |