Rdis provides a scriptable interface through lua. Lua has a semi-OOP model through metatables. When we refer to, "objects," we are referring to lua tables with metatables.
Instead of interacting directly with the objects used by rdis, the interface obtains a copy of requested objects. These can be modified and then passed back to rdis.
When rdis loads a file, it will check for ~/.rdis.lua. If the file is found, it is opened, loaded and run each time an rdis object is created.
Rdis makes no limitations on the lua environment. While this opens a wealth of possibilities, one of those possibilities is os.execute("rm -rf /") or worse. Be careful what you run.
Rdis Lua Cheat Sheet
Lua does not have native support for the type uint64_t. Support of this type can be accomplished via two means: modify lua or provide a uint64 object. We have elected to provide a uint64 object. This is cleaner, allows the use of luajit, and prevents us from having to distribute a custom version of lua with rdis.
Uint64 is used extensively through the rdis lua API.
uint64 uint64 (string)
uint64 uint64 (number)
The function uint64() accepts either a string or a number and returns a uint64 object. When uint64 is given a string, the string is passed to strtoull to fetch the corresponding 64-bit value.
uint64 uint64.__add (uint64)
uint64 uint64.__sub (uint64)
uint64 uint64.__mul (uint64)
uint64 uint64.__div (uint64)
uint64 uint64.__mod (uint64)
boolean uint64.__eq (uint64)
boolean uint64.__lt (uint64)
boolean uint64.__le (uint64)
string uint64.__tostring ()
string uint64.string ()
If you are familiar with lua, then you already know these metamethods. Lua uses these methods internally to override operators on the uint64 object. An example follows:
a = uint64(32)
b = uint64("0xdeadbeef") c = uint64("0xdeadbeeffeebdaed") d = (((a + b) - c) * a) / b) % c print(a) rdis.console(tostring(a) .. " " .. b:string()) if a == b then print("a == b") end
nil rdis.console (string)
Sends the text to the rdis console window. A newline will be appended.
table rdis.functions ()
Returns following lua table:
[uint64 address] -> string function_label
integer rdis.peek (uint64)
Returns the byte at the given virtual address, or nil if the address is invalid.
node rdis.node (uint64)
Returns a node from the Control Flow Graph at the given index. If no node was found with the given index, an error is thrown. A node's index is the same as the address of the first instruction found in that node.
uint64 node:index ()
Returns the node's index.
table node:edges ()
Returns a table with values of type edge. These edges contain the node's predecessors and successors. Determine if an edge is a predecessor or successor by comparing node:index() against edge:head() or edge:tail().
table node:instructions ()
Returns a table with values of type ins. These are the node's instructions.
uint64 edge:head ()
Returns the index of this edge's head node.
uint64 edge:tail ()
Returns the index of this edge's tail node.
uint64 ins:address ()
Returns the virtual address where the instruction was found.
uint64 ins:target ()
Returns the instructions, "Target." A target is the address an instruction will branch to. This is mostly useful for call instructions. For conditional branches, this is the address taken if the condition is true.
Not all instructions have a target. If the instruction does not have a target, nil will be returned instead. No error will be thrown as the absence of a target is a valid state and not an error.
table ins:bytes ()
Returns a table with values of type integer containing the bytes that were disassembled to achieve this instruction.
string ins:description ()
Returns this instructions textual description. An example is "mov eax, ebx". If the instruction has no description, nil is returned. If the instruction has no description, you should probably let someone know.
string ins:comment ()
Returns this instructions comments. Comments are created by the user. If no comment exists, nil is returned.