본문 바로가기

카테고리 없음

Quickbms

===============================================
4) How to create scripts (for developers only!)
===============================================
 
Originally the tool was created for myself for making me able to write quick extractors for simple archives immediately without writing a line of C but it revealed to be a so powerful tool that now I use it really for everything included the parsing of some protocols and much more.
 
So, how to write these scripts?
Well I guess that giving a look at http://wiki.xentax.com/index.php/BMS is a good first step to understand at least the basis of this language originally written by Mike Zuurman (alias Mr.Mouse of XeNTaX) in the far 1997.
Then it's good to take a look at the various examples provided on http://aluigi.org/papers.htm#quickbms and
http://forum.xentax.com/viewforum.php?f=10 and obviously to the following list of available commands and their description.
 
A programming knowledge and background is not required but it's very useful for entering in the "logic" of the scripts, while it's required the full knowledge of the format to implement: reversing is ever useful for figuring the needed fields.
 
Luckily in the extraction process is not needed to know all the fields of an archive so a field like a CRC just doesn't matter while the important fields are ever the filename, the offset and the size of the files to extract.
You can notice all these useless fields in my scripts because I assign them the name DUMMY.
 
Note that I will try to keep the following documentation updated as much as I can, in any case refer also to the source code of quickbms.c for any other technical doubt or possible additions or particular behaviour of the tool in particular circumstances. The fields between [ ] are optionals.
 
---
 
A quick list of available commands is available also when QuickBMS is launched with the -c option, and REMEMBER to read the notes specified there like the fact that:
 
- everything is considered a variable except if it starts with a number in which case it's considered a numeric constant so when in this text I talk about VAR, STRING and other types of data I refer EVER to both variables and constants because they are EXACTLY the SAME thing
 
- All commands and the names of the variables are case INsensitive so "get OFFSET" is the same as "GeT oFfSeT"
 
- Everything works with signed 32 bit numbers (-2147483648 to 2147483647) so QuickBMS at the moment could not work well with files over 2 gigabytes but it can seek on files of 4 gigabytes so consider the following limits:
- max 4gb for archives
- max 2gb for the contained files
 
- The so called constant strings (depends by the context of the command) are handled as strings in C notation like "\x12\x34\\hello\"bye\0" and so on, in this case you must know a bit how this representation works.
the keyword is "C language escape characters" or escape sequences,
they are very simple, take a look here:
http://msdn.microsoft.com/en-us/library/h21280bw%28VS.80%29.aspx
http://www.acm.uiuc.edu/webmonkeys/book/c_guide/1.1.html
 
- Are supported also hexadecimal numbers if they start with 0x so 1234 and 0x4d2 are the same thing
 
- Any operation made on fields bigger than 8 bits is controlled by the global endianess, which means that any number and unicode field is read in little endian by default otherwise it's valid the endianess specified with the Endian command
 
- Comments can be used in C (// and /* */) and BMS syntax (#)
 
File numbers:
every file opened in QuickBMS has a number assigned to it and in all the commands that access to files this number is 0 (main file) if not specified. The first opened file is the input archive to which is assigned the number 0 (zero), the others must be opened with the Open command
 
MEMORY_FILEs:
this is a particular type of temporary file which resides in memory and works exactly like a normal file.
it's extremely useful for doing tons of things and are supported various memory files: MEMORY_FILE, MEMORY_FILE2, MEMORY_FILE3 and so on. MEMORY_FILE and MEMORY_FILE1 are the same.
 
TEMPORARY_FILE:
exists also another type of file called TEMPORARY_FILE which instead resides phisically on the hard-disk with that exact name. Although its "temporary" name it's not deleted by the output folder (anyway at the end of the process QuickBMS will ask if the user wants to remove it or not) and is created even when it's used the -l option for listing the files which makes it ideal in certains situations like when it's used a chunks based file system.
.
indeed in this case using a MEMORY_FILE is a bad idea because the
continuous reallocation of the memory makes it terribly slow except
if you have pre-allocated the space of the MEMORY_FILE with the
PutVarChr command but in that case remains the problem of using too
much memory.
.
for using the temporary file remember to use it like in the following
example:
log TEMPORARY_FILE 0 0 # reset it in case it already exists (optional)
append # enables the append mode
...
log TEMPORARY_FILE OFFSET SIZE
...
append # disable the append mode
open "." TEMPORARY_FILE 1 # open the temporary file on the file number 1
 
 
Types of variables supported, also know as datatypes or types:
STRING null delimited string (one byte for each char)
BYTE 8 bit, 0 to 0xff
SHORT 16 bit (aka INT), 0 to 0xffff
THREEBYTE 24 bit, 0 to 0xffffff
LONG 32 bit, 0 to 0xffffffff
LONGLONG fake 64 bit, so only 0 to 0xffffffff but takes 8 bytes in Get
FLOAT 32 bit, 123.345 is got as 123
DOUBLE 64 bit, 123.345 is got as 123
LONGDOUBLE 96 bit, 123.345 is got as 123
VARIABLE read byte per byte till the byte is negative
VARIABLE2 Unreal engine index numbers
VARIANT VB/C++ variant type (http://en.wikipedia.org/wiki/Variant_type)
TIME time_t Unix 32bit time
TIME64 64bit time used as FILETIME on Windows
CLSID ClassID like 00000000-0000-0001-0000-000000000000
IPV4 7f 00 00 01 = "127.0.0.1"
IPV6 like 2001:0db8:85a3:0000:0000:8a2e:0370:7334
ASM x86 assembly
ASIZE special type used to return the size of the opened file, used only with the GET command
FILENAME special type used to return the name of the opened file
like "myfile.zip", used only with the GET command
BASENAME special type used to return the base name of the opened
file like "myfile", used only with the GET command
EXTENSION special type used to return the extension of the opened
file like "zip", used only with the GET command
UNICODE special type used for unicode utf16 strings, the endianess of the utf16 is the same used globally in the
script (watch the Endian command), it's used also for converting an unicode string to an ascii one:
Set ASCII_STRING UNICODE UNICODE_STRING
obviously this is a fake utf16 so it's good only for english strings
BINARY special type used for binary strings in C notation like
"\xff\x00\x12\x34", used mainly as a constant
COMPRESSED a special type used for setting big strings and memory files using a small amount of text,
for using this type you must take the original text/file, compress it with zlib (you can use
my packzip tool) and then encoding the outputfile with base64 (you can use my bde64 tool) and placing the result like the following:
set MEMORY_FILE compressed eNrtwbEJACAMBMBecIfvnMUxPuEJAe0UHN81LLzrbYKwDOjI96IN1cLveRfAGqYu
this type is very useful if you want to embed a dll inside
a script without wasting much space
LINE special type used for carriage return/line feed delimited
string (so any string ending with a 0x00, 0x0a or 0x0d)
FULLNAME full path of the file, in reality at the moment it returns the same path used in the input filename
CURRENT_FOLDER the path from which has been launched QuickBMS
FILE_FOLDER the path of the loaded input file
BMS_FOLDER the folder where is located the bms script
OUTPUT_FOLDER the extraction folder (the last argument of QuickBMS)
INPUT_FOLDER same as above
ALLOC a type used only in the Set command for a particular thing
 
 
And now the list of commands in the same order in which they are listed
in the QuickBMS source code in the function parse_bms():
.......................................................................
Clog NAME OFFSET ZSIZE SIZE [FILENUM]
Extracts the file decompressing it in real-time, this operation doesn't affect the current position of the input file.
the decompression algorithm used in the operation is decided by the ComType command.
The content of the extracted file can be decrypted automatically using the Encryption command.
 
arguments:
NAME name of the output file
OFFSET position of the archive where is located the file
ZSIZE size of the compressed data in the archive
SIZE size of the uncompressed file
FILENUM number of the file associated to the archive (0)
 
examples:
Clog NAME OFFSET ZSIZE SIZE
Clog "dump.dat" 0 ZSIZE 10000000 # the file will have the real size and not 10000000
.......................................................................
FindLoc VAR TYPE STRING [FILENUM] [ERR_VALUE]
finds the first occurrency of a given string or number from the current offset of the archive.
it's usually used when the format of the archive is not known or it is a particular text file... not much used.
 
arguments:
VAR the variable which will receive the offset of the occurrency
TYPE can be STRING, UNICODE or a number
STRING string in C notation or number, depending by the TYPE
FILENUM number of the file associated to the archive (0)
ERR_VALUE by default FindLoc terminates the script if no string is found but if ERR_VALUE is specified this value will
be assigned to VAR without terminating when there are no other occurrencies
 
examples:
For
FindLoc OFFSET string "filename="
...
FindLoc OFFSET string "filename=" 0 ""
if OFFSET == ""
cleanexit
endif
Next
 
.......................................................................
For [VAR] [OP] [VALUE] [COND] [VAR]
...
Next [VAR]
a classical "for" loop with initializers, conditions and incrementers. There is also the Break instruction available to
break the loop at any moment (note that the Break instruction is not suggested in presence of multiple For
because in some rare cases it could give problems).
Next is the command which delimits the loop and at the same time increments the given variable if specified.
practically it means:
- give VALUE to VAR (or performs a mathematical operation on it)
- perform a loop till VAR is "condition" than the other VAR
- perform all the operations between For and Next
- increment VAR all the parameters are optionals.
 
arguments:
VAR variable to which assign a value
OP from version 0.3.10 this value can be any of the available Math operators (so not only the classical '=')
VALUE value to assign to the variable or part of the math operation
COND condition, the same of the IF command
VAR second part of the condition
 
examples:
For i = 0 < FILES
...
next i
For
# do what you want here, this is an endless loop
Next
For VAR1 = VAR1 != VAR2
# this is exactly the same of using while(VAR1 != VAR2) {...} in C
Next
 
.......................................................................
Get VAR TYPE [FILENUM]
reads strings and numbers from the open files, it's also the most used command.
 
arguments:
VAR variable which will receive the read data
TYPE watch the description of the types explained before
FILENUM number of the file associated to the archive (0)
 
examples:
Get OFFSET long
Get NAME string
 
.......................................................................
GetDString VAR LENGTH [FILENUM]
reads a defined amount of data from the file and stores it in the given variable.
useful with filenames and other strings that have a length specified in a previous 8, 16 or 32 bit field.
 
arguments:
VAR variable which will receive the read data
LENGTH amount of bytes to read
FILENUM number of the file associated to the archive (0)
 
examples:
GetDString NAME NAME_LENGTH
GetDString NAME 0x100
 
.......................................................................
GoTo OFFSET [FILENUM] [TYPE]
go to the given absolute position of the file, the classical fseek
 
arguments:
OFFSET position to reach, if it's negative it will be considered an "OFFSET bytes from the end of the file" position
note that from QuickBMS 0.3.5a only the constants can be negative with GoTo (even keeping the 4gb
limit in any case), all the variables will be handled as unsigned (0 to 0xffffffff)
FILENUM number of the file associated to the archive (0)
TYPE SEEK_SET (default), SEEK_CUR, SEEK_END
 
examples:
GoTo OFFSET
GoTo 0x100
GoTo -4 # 4 bytes before the end of the file
 
.......................................................................
IDString [FILENUM] STRING
Terminates if the signature at the current position of the file differs than the provided string.
from version 0.4.5 if the string doesn't match and is 4 bytes long QuickBMS will swap and recompare it, if it matches
the endianess will be changed making the majority of the scripts written for an architecture (for example PC) virtually compatible with others (for example Xbox360).
 
arguments
FILENUM number of the file associated to the archive (0)
STRING string in C notation
 
examples:
IDString "PK\x03\x04"
IDString " KAP"
 
.......................................................................
Log NAME OFFSET SIZE [FILENUM]
Extracts the file, this operation doesn't affect the current position of the input file.
The content of the extracted file can be decrypted automatically using the Encryption command.
 
arguments:
NAME name of the output file
OFFSET position in the archive where is located the file
SIZE amount of the data to extract
FILENUM number of the file associated to the archive (0)
 
examples:
Log NAME OFFSET SIZE
Log "dump.dat" 0 SIZE
 
.......................................................................
Math VAR OP VAR
performs a mathematical operation between the two variables and places the result in the first one.
note that for compatibility all the operations are performed using signed 32 bit numbers by default.
this makes the difference with some operation like the shift ones, so pay attention!
for unsigned operations I have implemented the 'u' additional OP from QuickBMS 0.3.14
 
arguments
VAR variable which acts as input and output
OP + sum
* multiplication
/ division
- substraction
^ xor
& and
| or
% modulus
! negation of var2 (0 becomes 1 and any other value becomes 0)
~ complement of var2 (like "xor 0xffffffff")
< shift left
> shift right
l rotate left
r rotate right
s byte swapping
w bit swapping
= assign var2 to var1
n negative value of var2 (so -var2)
a absolute value of var2
v radix
p power
x alignment, examples:
var1=1, var2=16, result=16
var1=16, var2=16, result=16
var1=17, var2=16, result=32
z common bitswapping:
var1=0xab, var2=4, result=0xba
var1=0xabcd, var2=4, result=0xdc
var1=0xabcd, var2=8, result=0xcdab
add a 'u' before or after OP for forcing the usage of unsigned operations useful with shift, divisions
and possibly other operations, any operation starting with a '?' will be considered a verbose operation,
for example ?add is the same of + QuickBMS supports also all the functions available in math.h like
?sin, ?cos, ?atan and so on
VAR other input variable
 
examples:
Math SIZE *= 0x100
Math OFFSET <<= 2
Math TMP = SIZE
Math TMP ~ TMP
Math TMP n TMP
Math TMP2 a TMP
Math SIZE u/= 5
Math RADIX v= 2
 
.......................................................................
Open FOLDER NAME [FILENUM] [EXISTS]
opens a file for reading, practically assigns a file number/id to an existent file that you want to use
 
arguments:
FOLDER FDDE, means that you want to open the file in the same location
of the input one which has the extension provided with NAME
FDSE, it will consider NAME as a file located in the same folder of the input file (very useful)
any other value is considered the folder where is located the file to load so use "."
for the current output folder
NAME read above, NAME can be also a ? in which case QuickBMS will ask the user to insert the name of
the file to open manually.
if NAME is "" then will be performed a flush operation that could be useful (or not?) only in write mode
FILENUM number of the file associated to the archive (0)
EXISTS if the file doesn't exist this variable will be set to
0 otherwise 1 (exists). by default QuickBMS terminates
with an error if the file doesn't exist.
 
examples:
Open FDDE DAT 0
Open FDDE IDX 1
Open FDSE "myfile.zip"
Open "." TEMPORARY_FILE 1
 
.......................................................................
SavePos VAR [FILENUM]
returns the current position of the file, like ftell
 
arguments:
VAR variable which will contain the offset
FILENUM number of the file associated to the archive (0)
 
examples:
SavePos OFFSET
 
.......................................................................
Set VAR [TYPE] VAR
command for assigning a constant or a variable to another variable
with the possibility of changing its type (like with unicode)
 
arguments:
VAR output variable or memory file
TYPE useless type, indeed it can be also not specified in which case will be used the String value.
it's useless because in QuickBMS doesn't exist a real difference between numbers and strings except some
cases (like unicode, filename, basename, extension and possibly others).
remember that here TYPE can have also the special BINARY type explained before or STRLEN used as
alternative at the Strlen command
VAR variable or constant to assign
 
examples:
Set i long 0
Set TMP long SIZE
Set TMPNAME NAME
Set MEMORY_FILE binary "\x12\x34\x56\x78"
Set ASCII_VAR unicode UNICODE_VAR # from unicode to string
 
.......................................................................
Do
...
While VAR COND VAR
a not so useful type of cycle where is performed the check of the condition at the end of the cycle... really rarely used.
if you need a C-like "while(...) {...}" use the For command.
 
arguments:
VAR first part of the condition
COND condition, check the If command below for additional info
VAR second part of the condition
 
examples:
Do
...
While OFFSET < MAX_OFFSET
 
.......................................................................
String VAR OP VAR
the equivalent of the Math command for the strings
 
arguments:
VAR input and output variable
OP = just a copy or if var2 is a number it will consider it a raw string:
var2="0x44434241", result="ABCD"
+ append the second string to the first one
- if the second variable is a positive number the string will be truncated at that amount of bytes
from the end
if the second variable is a negative number the string will be truncated at that amount of bytes
from the beginning
otherwise will be removed all the occurrencies of the second string in the variable
^ xoring of the string with the second one (looped if shorter)
< var1="thisisastring", var2="4", result="isastring"
% truncate the variable at the position obtained by the modulus of its length and the number in
the second variable
& var1="thisisastring", var2="isa", result="isastring"
| var1="thisisastring", var2="isa", result="string"
> if the second variable is a number:
var1="thisisastring", var2="4", result="thisisast"
otherwise:
var1="thisisastring", var2="isa", result="this"
b byte2hex of var2: var2="abc", result="616263"
B as above but uses the var2 as a null delimited string (strlen)
h hex2byte of var2: var2="616263", result="abc"
e experimental encryption based on the Encryption command
E as above but uses the var2 as a null delimited string (strlen)
c experimental compression based on the ComType command
C as above but uses the var2 as a null delimited string (strlen)
u var2="hello", result="HELLO"
l var2="HELLO", result="hello"
p a printf-like experimental work-around
r reversed string
R replace chars
VAR the second variable or string
 
examples:
string FULLPATH += NAME
string FULLPATH += \
string NAME -= ".zip"
string NAME -= 4
string PATH R= "." "/"
string FULLPATH p= "c:\folder\%04x%04x.dat" VAR1 VAR2
 
.......................................................................
CleanExit
terminates the script, it's possible also to use just Exit
 
.......................................................................
If VAR COND VAR
...
[Elif VAR COND VAR]
...
[Else]
...
EndIf
checks various conditions and performes the needed operation when the condition is verified, translated:
- If is ever the first condition
- Elif is another condition and can be used endless times
- Else is the operation to do when no conditions are met, the last
- EndIf delimits the If command
 
arguments:
VAR first part of the condition
COND valid for both strings and numbers:
< minor
> major
!= different
== equal
>= major/equal
<= minor/equal
& string: var2 is included in var1
number: logical AND
^ string: equal
number: logical XOR
| number: logical OR
% number: modulus
/ number: division
<< number: shift left
>> number: shift right
! number: negation
!! number: true, use it to know if VAR is non-zero
~ number: complement
ext compares the string after the last dot
basename compares the string before the last dot
any other operation supported by the Math command (valid
only for the numeric variables)
add a 'u' before COND for forcing the usage of unsigned
operations useful with shift, divisions and possibly other
operations
VAR second part of the condition
 
Examples:
If NAME != ""
...
Endif
If MASK & 1
Elif MASK & 2
Elif MASK & 4
Elif MASK & 8
Else
Endif
 
.......................................................................
GetCT VAR TYPE CHAR [FILENUM]
reads a string till the reaching of the CHAR delimiter.
 
arguments
VAR output variable
TYPE ignored because doesn't exist a type in this operation
CHAR the delimiter character as 8bit number
FILENUM number of the file associated to the archive (0)
 
examples:
GetCT NAME string 0x0a
GetCT NAME string 0x3b
set DELIMITER_BYTE long 0x0a
GetCT NAME string DELIMITER_BYTE
 
.......................................................................
ComType ALGO [DICT]
selects the specified compression algorithm to use with the Clog command.
from version 0.3.8 of QuickBMS I have also added the possibility of choosing a number as ALGO for an "utopic" idea about a scanner for being able to guess the possible compression algorithm in an unknown compressed data block:
http://aluigi.org/papers/bms/comtype_scan2.bat
http://aluigi.org/papers/bms/comtype_scan2.bms
comtype_scan2.bat comtype_scan2.bms input_file output_folder
comtype_scan2.bat comtype_scan2.bms input_file output_folder uncompressed_size
obviously this feature is only for advanced people who knows exactly what they are doing... and works really perfectly.
note that some algorithms work only on Windows
 
arguments:
ALGO Various (up to 100 Compression Algorithm)
DICT an optional C string containing the bytes of the dictionary
or particular parameters depending by the chosen algorithm
 
.......................................................................
ReverseLong VAR
classical swap that inverts a 32bit variable from 0x44332211 to 0x11223344 and viceversa.
 
arguments:
VAR variable to flip
 
.......................................................................
ReverseShort VAR
classical swap that inverts a 16bit variable from 0x2211 to 0x1122 and viceversa.
 
arguments:
VAR variable to flip
 
.......................................................................
ReverseLongLong VAR
classical swap that inverts a 32bit variable from 0x8877665544332211 to 0x1122334455667788 and viceversa.
this command works only with quickbms_4gb_files.exe
 
arguments:
VAR variable to flip
 
.......................................................................
Endian TYPE
changes the current global endianess of the read/written data, the default one is little endian.
 
arguments:
TYPE little/intel endianess where 0x11223344 is stored as 44 33 22 11
big/network endianess where 0x11223344 is stored as 11 22 33 44
 
Examples:
print "little endian"
endian big
print "big endian"
endian little
print "little endian"
 
.......................................................................
FileXOR SEQ [OFFSET]
Any read operation (Get, *Log and so on) on any file will perform also the xoring of the read data with the numbers contained in the given string or in the given variable.
The OFFSET field by default is zero which means that if the data must be xored with more than one byte (a "xor key") the first byte of the xor key is the first byte at OFFSET which is 0 by default (beginning of the file).
resuming: the FileXOR command works with ANY file access
 
arguments:
SEQ sequence of space-separated 8bit numbers, it can be a:
- sequence of bytes separated by space like 0x12 or "0x12 0x34 0x56" or directly a C hex string like
"\x12\x34\x56"
- a numeric variable
at the moment is not possible to use a key in string mode (use the Encryption command for doing it)
so if you have a string convert it to a numeric sequence first.
set it to 0 or "" for disabling the xor
OFFSET needed only for the xor key.
if the archive is xored with a xor key from its beginning
(so first byte of the archive xored with the first one
of the key) this argument is usually not necessary
if instead it's the file to extract that is xored, this
argument must have the same offset of the file (so
just reuse the same OFFSET used in Log)
 
examples:
filexor 0xff
filexor "0x12 0x34 123 255"
filexor MYXORBYTE
filexor "0x12 0x34 123 255" OFFSET
filexor "\x12\x34\x7b\xff"
Log NAME OFFSET SIZE
 
.......................................................................
FileRot SEQ [OFFSET]
Exactly as for FileXOR but it performs a sum operation. for example if SEQ is 0x01 and the file contains "hello" it
will become "ifmmp" while if SEQ is -1 or 0xff it will become "gdkkn".
-1 and 0xff are the same because it's a 8 bit number.
resuming: the FileRot command works with ANY file access
 
watch the previous arguments and examples.
 
.......................................................................
FileCrypt SEQ [OFFSET]
experimental, works only if has been already specified and enabled the Encryption command and practically applies
those algorithms to the normal file reading operations.
note that at the moment OFFSET is unused and SEQ can be only 1 for activating it and "" or 0 to disable it.
remember that the encryption algorithms usually work on blocks of data so this command is probably useless, consider
it only a test that costed me nothing to implement.
 
full example:
get NAMESZ long
encryption xor "\x11\x22\x33\x44"
filecrypt 1
getdstring NAME NAMESZ
filecrypt 0
encryption ""
 
.......................................................................
Strlen VAR VAR
calculates the length of the second variable and stores it in the first one.
the length is the amount of bytes till the reaching of a 0 delimiter.
note that for practical reasons this command can be emulated also using "set VAR strlen VAR"
 
arguments
VAR destination variable which will contain the length
VAR variable of which calculating the length
 
examples
strlen NAME_LENGTH NAME
strlen NAMESZ NAME
 
.......................................................................
GetVarChr VAR VAR OFFSET [TYPE]
a particular and sometimes very useful command which works exactly
like accessing to an array of elements contained in the second
variable (so a string or a memory file).
this simple but effective method allows the customization of strings
and variables for example for creating a custom header (like a DDS)
and moreover for performing operations on a piece of the memory (like
a custom encryption algorithm).
some real examples are my Deer Hunter 2004/2005 scripts.
 
arguments
VAR destination variable which will contain the read element
VAR variable or memory file from which you want to get the
element
OFFSET position of the second variable where taking the element
TYPE if not specified it's a BYTE so a 8bit number, you can
choose any of the available data types and it will go
in the destination variable
 
examples:
For i = 0 < SIZE
GetVarChr TMP MEMORY_FILE i
GetVarChr TMP MEMORY_FILE i long
# GetVarChr TMP MEMORY_FILE i string
Next i
 
.......................................................................
PutVarChr VAR OFFSET VAR [TYPE]
the "write-mode" alternative of the previous command which allows to perform various complex operations with custom algorithms (like in my Deer Hunter 2004/2005 scripts). note that from version 0.3.3 PutVarChr can be also used as an allocator of memory that could be useful for example in the implementation of custom decompression algorithms or, moreover, for pre-allocating a MEMORY_FILE avoiding to waste time and memory with the incremental allocation, remember only to use Log MEMORY_FILE 0 0 after it for resetting the position of the MEMORY_FILE.
 
arguments
VAR variable or memory file to which you want to put the
element
OFFSET position of the first variable where placing the element
VAR source variable which will contain the element to write
TYPE if not specified it's a BYTE so a 8bit number, you can
choose any of the available data types and it will go
in the destination variable
 
examples:
For i = 0 < SIZE
GetVarChr TMP MEMORY_FILE i
Math TMP ^= 0xff
PutVarChr MEMORY_FILE i TMP
Next i
 
.......................................................................
Debug [MODE]
switch command which enables the -v option in real-time for a specific portion of the script, used only for debugging.
if MODE is specified (any positive or negative number) then QuickBMS will only display the content of the variables
read/written with the Get/Put commands... it's really very useful and cool for debugging file formats and protocols in an
easy way.
 
.......................................................................
Padding VAR [FILENUM]
when called it performs an automatic GoTo to the next position of the file skipping the padded data.
imagine to have a file where it's used an alignment of 4 bytes and your current file offset is 0x39, if you use Padding
4 the offset will be automatically changed to 0x3c.
 
arguments:
VAR size of the alignment, for example 4 or 16 and so on
FILENUM number of the file associated to the archive (0)
 
examples:
Get NAME string
Padding 4
get OFFSET long
 
.......................................................................
Append
switch command which enables the append mode in the *Log commands, so if the output filename is still the same
it will be not overwritten while it will be concatenated.
note that the user must ever confirm the appending for security reasons.
 
examples:
append
Log "dump.dat" 0 0x10
Log "dump.dat" 0x10 0x100
 
the following is a particular example for allocating a MEMORY_FILE (from version 0.3.3) and using it instead of
TEMPORARY_FILE saving space on the disk and performances:
math TMP = CHUNKS
math TMP *= 0x8000
log MEMORY_FILE 0 0
putvarchr MEMORY_FILE TMP 0 # improves the speed with pre-allocation
log MEMORY_FILE 0 0 # reset the position and size of the file
append
for i = 0 < CHUNKS
...
clog MEMORY_FILE OFFSET ZSIZE 0x8000
next i
get SIZE asize MEMORY_FILE
 
.......................................................................
Encryption ALGO KEY [IVEC] [MODE] [KEYLEN]
Most interesting commands which allow to set a decryption algorithm used for any read operation on the files.
resuming: the Encryption command works ONLY with Log and CLog.
from version 0.3.15 QuickBMS supports also the hashing algorithms of OpenSSL, the hash will be placed in binary mode
in the variable QUICKBMS_HASH and in hex mode in QUICKBMS_HEXHASH.
 
arguments:
ALGO (Various Encryption Algorithm)
KEY the key to use in C notation like "\x11\x22\x33\x44" or
"this is my key"
from version 0.3.9 this value can be also a variable or a
memory file
IVEC the ivec to use in C notation, an ivec is an additional
key used for increasing the security of encryption
algorithms that are usually defined as ECB without ivec
and CBC (and other names) with ivec
MODE 0 for decryption (default), 1 for forcing the encryption mode
if no ivec is used remember to place a "" at its place
KEYLEN forces the usage of a certain length of the key, this one
has been introduced only for avoiding the problem of using
a variable as KEY containing zeroes in it
 
examples:
Encryption aes "0123456789abcdef" "" 1 # encryption without ivec
Log MEMORY_FILE 0 SIZE
Encryption aes "0123456789abcdef" # decryption without ivec
Log "redecrypted_file.dat" 0 SIZE MEMORY_FILE
Encryption aes "\x12\x34\x56\x78"
set MEMORY_FILE binary "\x12\x34\x56\x78"
Encryption aes MEMORY_FILE
Encryption aes MY_VARIABLE
Encryption md5 ""
 
.......................................................................
Print MESSAGE
prints a string in C notation with the values of the variables if they are specified between two % chars.
from version 0.4.5 is possible to specify the maximum amount of bytes to visualize and if they must be showed in
hex or dump mode specifying some flags after a '|' like in the examples.
 
arguments:
MESSAGE C notation string, each %VAR% word is converted to its value
 
examples:
print "the variable OFFSET of the file %FILENAME% has the value %OFFSET%"
print "this is the first line\nthis is the second line\n"
print "variable %VAR% and %VAR2%"
print "variable %VAR|h% and %VAR2|hex%"
print "variable %VAR|3% and %VAR2|4%"
print "variable %VAR|3h% and %VAR2|h4%"
print "variable %VAR|dump16%"
 
.......................................................................
GetArray VAR ARRAY VAR
and
PutArray ARRAY VAR VAR
experimental commands implemented for a possible future usage but that at the moment have been used enough
rarely although very useful. they work on a dynamic array where is possible to store data, something like a temporary
place or a stack.
 
examples:
PutArray 0 0 FIRST_VAR
PutArray 0 1 SECOND_VAR
PutArray FIRST_VAR 0 0
PutArray SECOND_VAR 0 1
 
.......................................................................
CallFunction NAME [KEEP_VAR] [ARG1] [ARG2] ... [ARGn]
StartFunction NAME
...
EndFunction
calling and declaration of a function identified by NAME where the
values of the variables are saved till the termination of the
function when they are restored.
it works very well for recursive archives like those used by "The
Void" and "Another Day" although it could result not much immediate
in its usage to understand but it's very powerful.
so remember the rule: the content of the variables is restored when
the function terminates, except if you set KEEP_VAR to 1.
it's a good idea to place all the functions (StartFunction till
EndFunction) at the end of the scripts.
From version 0.5.3 I have added the usage of optional arguments
passed to the function, they will have the name of the function plus
ARGnumber, for example: MYFUNCTION_ARG1 amd MYFUNCTION_ARG2.
 
arguments:
NAME name assigned to the function
KEEP_VAR set to 1 if you want to keep the content of the variables
without resetting them, in short words:
0 = for recursive functions (default)
1 = for normal functions that change variables
 
examples:
watch thevoid.bms and fear.bms
 
.......................................................................
ScanDir PATH NAME SIZE [FILTER]
function without a real usage, it simply scans the PATH folder and
fills the NAME and SIZE variables with the name and the size of
each file found.
at the moment this function doesn't have a purpose so ignore it.
use -F in quickbms for filtering the scanned files if you used a
folder as input (I tell this because some users could think to use
this command for that purpose which is not needed).
 
arguments:
PATH must be ".", the current folder
NAME output variable which receives the name of the file, it
will be "" when there are no other files
SIZE output variable which receives the size of the file, it
will be -1 when there are no other files
FILTER same job as -F, this filter is valid only if -F wasn't
specified
 
examples:
For
ScanDir "." NAME SIZE
if NAME == ""
cleanexit
endif
Next
...
For
ScanDir "." NAME SIZE "*.jpg"
if NAME == ""
cleanexit
endif
Next
 
.......................................................................
CallDLL DLLNAME FUNC/OFF CONV RET [ARG1] [ARG2] ... [ARGn]
this is the command which allows to use plugins inside QuickBMS.
the idea came from the possibility of using the custom
decompression/decryption functions (both exported and internals)
located in executables and dlls avoiding the boring reversing of
all the functions.
works with both real files and MEMORY_FILEs (even if they contain
dll data!)
unfortunately this is not much possible with the functions got from
executables where are used static variables due to some technical
reasons (memory addresses that don't match due to the different
relocation of the executable inside the memory), for example if the
function uses the memory between 006c0000 and 006d0000 it's highly
possible that such range of memory is not allocated or is already
in use because the executable has not been loaded (LoadLibrary) in
its original address because already occupied.
obviously there are no problems with the dlls.
note that you can even use a dll inside a MEMORY_FILE but be sure
it's not packed because couldn't work.
 
arguments:
DLLNAME name of the dll or executable where is located the
function, example "mylib.dll"
QuickBMS can even load raw binary files that contain
only the dumped function... very useful
FUNC/OFF it can be the name of the function to import in which
case it must be exported by the dll/exe
or the relative offset where is located the function,
remember that the relative offset is NOT the absolute
one but it's the offset related to the image base of
the exe/dll (so if normally the dll loads at offset
10000000 and the function is at 10012345 then the
offset is 0x12345)
CONV calling convention:
stdcall: aka winapi, used by default in Visual C
cdecl: used by almost any other C/C++ compiler
fastcall: Microsoft/gcc fastcall
borland: the fastcall convension used by the Borland
compilers like Delphi
watcom
pascal
safecall
syscall
optlink
carion
thiscall
RET the variable which will contain the value returned by
the function, use "" if there is no return value
[ARGS] all the arguments of the function
from version 0.3.5 QuickBMS implements also the pointer
to arguments when they are preceded by a & or a * like
&SIZE which means that the dll/code receives the
pointer to that variable and can modify its content.
it works only with numeric variables
 
examples:
idstring LZ2K
get SIZE long
get ZSIZE long
log MEMORY_FILE 0xc ZSIZE
putvarchr MEMORY_FILE2 SIZE 0 # like malloc
#calldll "TransformersDemo.exe" 0x263c50 cdecl "" MEMORY_FILE MEMORY_FILE2 ZSIZE SIZE # 00663C50
calldll "unlzk.dll" "unlz2k" cdecl SIZE MEMORY_FILE MEMORY_FILE2 ZSIZE SIZE
log "dump.dat" 0 SIZE MEMORY_FILE2
 
.......................................................................
Put VAR TYPE [FILENUM]
...
PutDString VAR LENGTH [FILENUM]
...
PutCT VAR TYPE CHAR [FILENUM]
...
these are EXACTLY like the Get* functions except for the fact that
they perform write operations.
for using these commands on a phisical file (so MEMORY_FILEs
excluded) MUST be used the -w option at runtime needed for both
technical and security reasons.
if you want to write a string without the NULL delimiter use:
putct "your_string" string -1
 
.......................................................................
GetBits VAR BITS [FILENUM]
this is an experimental function for reading bits from the files.
when you use a GoTo function or change the current offset of the
file with a Get* command the variable containing the bit position
(practically the amount of bits read from the previously byte taken
from the file) will be set to 0.
note that the function is 100% endian compatible so the result
changes if you choose the little or big endian mode, remember it in
case the results don't match what you expected.
 
arguments:
VAR destination variable, can be a number if the bits are
from 0 to 32 or a string for major sizes
BITS number of bits to read
FILENUM number of the file associated to the archive (0)
 
.......................................................................
PutBits VAR BITS [FILENUM]
write mode, same format as GetBits
 
.......................................................................
 
From version 0.5 QuickBMS can handle also some minimalistic and
experimental C structures like:
 
debug 1 # needed to show the collected informations
struct test {
int var1;
char var2;
char *mystring;
uint8_t data[10];
}
 
These operations are all converted to Get* commands while they are
converted in Put* if there is a '=' after them, like:
 
debug 1
struct test {
int var1 = 0x11111111;
char var2 = 0x22;
char *mystring = "hello";
uint8_t data[10] = OTHER_VAR;
}
 
Maybe in future versions it could be improved but for the moment it's
classified as an experimental and secondary feature.