Rugosa includes an interactive shell tool created with cmd2 for emulating and traversing a given binary.
The shell tool can be started using the rugosa
command followed by the path to the binary file to analyze.
This will open a new shell with the current emulation context pointing to the entry point of the binary.
$ rugosa binary.exe
____
| _ \ _ _ __ _ ___ ___ __ _
| |_) | | | |/ _` |/ _ \/ __|/ _` |
| _ <| |_| | (_| | (_) \__ \ (_| |
|_| \_\\__,_|\__, |\___/|___/\__,_|
|___/ v0.11.0
Department of Defense Cyber Crime Center (DC3)
------------ ---------------------------------
File /home/ubuntu/dev/data/binary.exe
Disassembler IDA
Processor x86
Compiler Visual C++
Bit size 32
Endianness LE
Entry Point 0x004014e0
------------ ---------------------------------
(0x004014e0)>
By default, rugosa will use the backend disassembler set by dragodis
which is determined by the DRAGODIS_DISASSEMBLER
environment variable.
The disassembler can also be provided within the command line using the --backend
flag.
Please ensure the disassembler used is first setup by following the instructions provided by dragodis.
rugosa binary.exe --backend ghidra
After startup a number of different commands defined below can be used to view the disassembly and traverse emulation.
Once finished the quit
or exit
command will exit the shell.
The following commands are used to display information about the disassembled binary.
Prints the decompiled code of the current function.
(0x00401150)> code
int __cdecl main(int argc, const char **argv, const char **envp)
{
sub_401030();
sub_4012A0("%s\n", aIdmmnVnsme);
sub_4012A0("%s\n", aVgqvQvpkleUkvj);
sub_4012A0("%s\n", aWkfRvjHAqltmEl);
sub_4012A0("%s\n", aKeoMwWpvkjcEjE);
sub_4012A0("%s\n", aDflaGpwkvMjiVL);
sub_4012A0("%s\n", aEgruGhbBiauCge);
sub_4012A0("%s\n", aCv3gV3pargv3qf);
sub_4012A0("%s\n", aC);
sub_4012A0("%s\n", asc_40C114);
sub_4012A0("%s\n", aQfbwfsqlFppb);
sub_4012A0("%s\n", aTsudfs);
sub_4012A0("%s\n", byte_40C138);
sub_4012A0("%s\n", a5VTr4vTrv4tV);
sub_4012A0("%s\n", aAkjdgbaKjgdbjk);
sub_4012A0("%s\n", asc_40C174);
sub_4012A0("%s\n", a4);
sub_4012A0("%s\n", asc_40C1C4);
sub_4012A0("%s\n", aLmfoghknlmgfoh);
return 0;
}
An address or target variable can be provided to print the code of another function.
(0x00401150)> code sub_401030
int sub_401030()
{
sub_401000(aIdmmnVnsme, 1);
sub_401000(aVgqvQvpkleUkvj, 2);
sub_401000(aWkfRvjHAqltmEl, 3);
sub_401000(aKeoMwWpvkjcEjE, 4);
sub_401000(aDflaGpwkvMjiVL, 5);
sub_401000(aEgruGhbBiauCge, 6);
sub_401000(aCv3gV3pargv3qf, 19);
sub_401000(aC, 23);
sub_401000(asc_40C114, 26);
sub_401000(aQfbwfsqlFppb, 35);
sub_401000(aTsudfs, 39);
sub_401000(byte_40C138, 64);
sub_401000(a5VTr4vTrv4tV, 70);
sub_401000(aAkjdgbaKjgdbjk, 115);
sub_401000(asc_40C174, 117);
sub_401000(a4, 119);
sub_401000(asc_40C1C4, 122);
return sub_401000(aLmfoghknlmgfoh, 127);
}
Lists the export symbols within the binary.
(0x00401150)> exports
address name num_references
---------- ------ ----------------
0x004014e0 start 0
Lists the functions of the binary.
(0x00401150)> functions
start end name
---------- ---------- ----------------------------
0x00401030 0x00401143 sub_401030
0x00401150 0x004012a0 _main
0x00401365 0x0040138a _fast_error_exit
0x0040138e 0x004014e0 ___tmainCRTStartup
0x004014e0 0x004014ea start
0x0040261c 0x00402661 __SEH_prolog4
0x00402661 0x00402675 __SEH_epilog4
0x00402680 0x0040280c SEH_405330
...
Aliases: func
, funcs
, function
The create
subcommand can be used to attempt to define a new function
when the disassembler has failed to discover it.
Under the hood, this is using the rugosa.func_utils.create_function()
utility to attempt to discover
function boundaries surrounding a given address and define it as a function.
(0x004014e0)> goto 0x40116f
Function doesn't exist at 0x0040116f
(0x004014e0)> functions create 0x40116f
Function created: _main @ 0x00401150
(0x004014e0)> goto 0x40116f
(0x0040116f)>
Prints the import symbols within the binary.
(0x0040116f)> imports
address thunk_address name namespace num_references num_calls
---------- --------------- ------------------------------------- ----------- ---------------- -----------
0x0040a000 GetCommandLineA KERNEL32 3 1
0x0040a004 EnterCriticalSection KERNEL32 8 4
0x0040a008 LeaveCriticalSection KERNEL32 8 4
0x0040a00c TerminateProcess KERNEL32 4 2
0x0040a010 GetCurrentProcess KERNEL32 4 2
0x0040a014 UnhandledExceptionFilter KERNEL32 6 3
0x0040a018 SetUnhandledExceptionFilter KERNEL32 8 4
0x0040a01c IsDebuggerPresent KERNEL32 4 2
0x0040a020 GetModuleHandleW KERNEL32 12 6
0x0040a024 Sleep KERNEL32 8 4
0x0040a028 GetProcAddress KERNEL32 20 14
0x0040a02c ExitProcess KERNEL32 2 1
0x0040a030 WriteFile KERNEL32 14 7
0x0040a034 GetStdHandle KERNEL32 4 2
0x0040a038 GetModuleFileNameA KERNEL32 4 2
0x0040a03c FreeEnvironmentStringsA KERNEL32 4 2
0x0040a040 GetEnvironmentStrings KERNEL32 2 1
0x0040a044 FreeEnvironmentStringsW KERNEL32 2 1
...
Prints information about the given address/target variable or the current instruction of the program counter.
(0x004028cf)> info 0x40a028
--------------- -----------------------------------
Name GetProcAddress
Address 0x0040a028
Size 4
Location .idata: 0x0040a000 --> 0x0040a110
Function
Type dword
Value 0xffffffff
References To 20
References From 0
Import KERNEL32/GetProcAddress: 0x0040a028
Export
Registers
Operands 0: ds:GetProcAddress
Variables
--------------- -----------------------------------
Aliases: i
, what
Prints the instruction for a given address/target variable or the current instruction of the program counter.
(0x0040148f)> instruction
cmp dword ptr [ebp-1Ch], 0
(0x0040148f)> instruction 0x401158
push offset aIdmmnVnsme; "Idmmn!Vnsme "
TIP
To have the current instruction always displayed in the prompt, set the display_instruction
setting.
(0x0040148f)> set display_instruction True
display_instruction - was: False
now: True
(0x0040148f: cmp dword ptr [ebp-1Ch], 0)>
Aliases: insn
Prints the references to/from the given address or target variable.
Args:
-i
/--include-instruction
will enable instruction/data text to be displayed.-d
/--direction
will set the direction of references to include. (defaults to both directions)
(0x00401150)> references GetProcAddress -i
direction type from_address from_text to_address to_text
----------- --------- -------------- ------------------------------ ------------ ----------
to code_call 0x004028cf call ds:GetProcAddress 0x0040a028 4294967295
to code_call 0x0040363d call ds:GetProcAddress 0x0040a028 4294967295
to code_call 0x004036b8 call ds:GetProcAddress 0x0040a028 4294967295
to code_call 0x00403790 call ebx ; GetProcAddress 0x0040a028 4294967295
to code_call 0x004037a0 call ebx ; GetProcAddress 0x0040a028 4294967295
to code_call 0x00403a24 call esi ; GetProcAddress 0x0040a028 4294967295
to code_call 0x00403a31 call esi ; GetProcAddress 0x0040a028 4294967295
to code_call 0x00403a3e call esi ; GetProcAddress 0x0040a028 4294967295
to code_call 0x00403a4b call esi ; GetProcAddress 0x0040a028 4294967295
to code_call 0x0040588f call esi ; GetProcAddress 0x0040a028 4294967295
to code_call 0x004058ac call esi ; GetProcAddress 0x0040a028 4294967295
to code_call 0x004058c1 call esi ; GetProcAddress 0x0040a028 4294967295
to code_call 0x004058d6 call esi ; GetProcAddress 0x0040a028 4294967295
to code_call 0x004058ee call esi ; GetProcAddress 0x0040a028 4294967295
to data_read 0x004028cf call ds:GetProcAddress 0x0040a028 4294967295
to data_read 0x0040363d call ds:GetProcAddress 0x0040a028 4294967295
to data_read 0x004036b8 call ds:GetProcAddress 0x0040a028 4294967295
to data_read 0x0040378a mov ebx, ds:GetProcAddress 0x0040a028 4294967295
to data_read 0x00403a18 mov esi, ds:GetProcAddress 0x0040a028 4294967295
to data_read 0x00405883 mov esi, ds:GetProcAddress 0x0040a028 4294967295
Aliases: ref
, refs
Searches disassembly for given regex pattern. Lists the first disassembly line containing the matched data along with the matched data itself.
Args:
-s
/--segment
restricts search to a given segment.-n
/--num
limits results to given number. (defaults to all results)
(0x004014e0)> search \x68.{4}\xe8.\x00\x00\x00
segment address text function data
--------- ---------- ---------------------------- ---------- -------------------------------------
.text 0x004011a5 push offset aS_3; "%s\n" _main b'hX\xc2@\x00\xe8\xf1\x00\x00\x00'
.text 0x004011b7 push offset aS_4; "%s\n" _main b'h\\\xc2@\x00\xe8\xdf\x00\x00\x00'
.text 0x004011c9 push offset aS_5; "%s\n" _main b'h`\xc2@\x00\xe8\xcd\x00\x00\x00'
.text 0x004011db push offset aS_6; "%s\n" _main b'hd\xc2@\x00\xe8\xbb\x00\x00\x00'
.text 0x004011ed push offset aS_7; "%s\n" _main b'hh\xc2@\x00\xe8\xa9\x00\x00\x00'
.text 0x004011ff push offset aS_8; "%s\n" _main b'hl\xc2@\x00\xe8\x97\x00\x00\x00'
.text 0x00401211 push offset aS_9; "%s\n" _main b'hp\xc2@\x00\xe8\x85\x00\x00\x00'
.text 0x00401223 push offset aS_10; "%s\n" _main b'ht\xc2@\x00\xe8s\x00\x00\x00'
.text 0x00401235 push offset aS_11; "%s\n" _main b'hx\xc2@\x00\xe8a\x00\x00\x00'
.text 0x00401247 push offset aS_12; "%s\n" _main b'h|\xc2@\x00\xe8O\x00\x00\x00'
.text 0x00401259 push offset aS_13; "%s\n" _main b'h\x80\xc2@\x00\xe8=\x00\x00\x00'
.text 0x0040126b push offset aS_14; "%s\n" _main b'h\x84\xc2@\x00\xe8+\x00\x00\x00'
.text 0x0040127d push offset aS_15; "%s\n" _main b'h\x88\xc2@\x00\xe8\x19\x00\x00\x00'
.text 0x0040128f push offset aS_16; "%s\n" _main b'h\x8c\xc2@\x00\xe8\x07\x00\x00\x00'
Lists the segments within the binary.
(0x004014e0)> segments
start end size name permissions bit_size initialized
---------- ---------- ------ ------ ------------- ---------- -------------
0x00401000 0x0040a000 36864 .text EXECUTE|READ 32 True
0x0040a000 0x0040a110 272 .idata READ 32 False
0x0040a110 0x0040c000 7920 .rdata READ 32 True
0x0040c000 0x0040f000 12288 .data WRITE|READ 32 True
Aliases: seg
Lists the stack variables within the current function.
(0x00401150)> stack
offset size data_type name
-------- ------ ------------- ------
0x4 4 int argc
0x8 4 const char ** argv
0xc 4 const char ** envp
Lists general information about the binary being analyzed.
(0x00401150)> status
------------ ---------------------------------
File /home/ubuntu/dev/data/binary.exe
Disassembler IDA
Processor x86
Compiler Visual C++
Bit size 32
Endianness LE
Entry Point 0x004014e0
------------ ---------------------------------
Lists the discovered strings within the binary.
Args:
--min
sets the minimum length for a valid string. (defaults to 3)--raw
writes out string data as raw binary when given an address or target variable.
(0x00401150)> strings
address size string
---------- ------ -----------------------------------------------------------------------------------------------------------------------------------------------------------------
0x0040a150 6 (null)
0x0040a160 6 (null)
0x0040a179 3 EEE
0x0040a189 7 ( 8PX
0x0040a191 6 700WP
0x0040a199 3
0x0040a1a0 7 `h````
0x0040a1a9 9 xpxxxx
0x0040a1b6 3
0x0040a1c4 14 CorExitProcess
0x0040a1d4 11 mscoree.dll
0x0040a1ec 14 runtime error
0x0040a200 13 TLOSS error
0x0040a210 12 SING error
0x0040a220 14 DOMAIN error
0x0040a230 154 R6034
An application has made an attempt to load the C runtime library incorrectly.
Please contact the application's support team for more information.
0x0040a2d0 246 R6033
- Attempt to use MSIL code from this assembly during native code initialization
This indicates a bug in your application. It is most likely the result of calling an MSIL-compiled (/clr) function from a native constructor or from DllMain.
0x0040a3c8 50 R6032
- not enough space for locale information
0x0040a400 98 R6031
- Attempt to initialize the CRT more than once.
This indicates a bug in your application.
0x0040a464 30 R6030
- CRT not initialized
...
An address or target variable can be provided to extract the string at a specific location.
Combined with --raw
, we can provide the raw data for output redirection or pipelining.
(0x00401150)> strings 0x40c000 --raw | hexdump -C
00000000 49 64 6d 6d 6e 21 56 6e 73 6d 65 20 |Idmmn!Vnsme |
0000000c
The following commands are used to control emulation.
Sets execution context to the given address or target variable. By default, this will cause rugosa to trace a path down from the beginning of the current function to the requested address and then emulate those instructions. The determined branch path can be viewed with the branch_history command and an alternative path can be selected using the alternative command.
Args:
-k
/--keep
determines whether to emulate using the currently set context. By default a new context is created.-d
/--depth
sets the number of calls up the stack to emulate first before starting the current function. (defaults to 0)-c
/--call-depth
sets the number of function calls deep within the current function we are allowed to emulate. (defaults to not emulating any function calls except hooked ones)-f
/--follow-loops
determines if loops will be followed during emulation. Otherwise, only direct pathing is used.
(0x1400015e0)> goto 0x14000173d
(0x14000173d)>
Aliases: g
Executes the next instruction(s). A count can be provided to emulate multiple instructions.
Args:
-c
/--call-depth
sets the number of function calls deep within the current function we are allowed to emulate. (defaults to not emulating any function calls except hooked ones)
(0x00401477)> next
(0x00401478)> next 5
(0x0040148f)>
Aliases: n
Executes instructions until we hit the given address/target variable or we reach a function return (which ever comes first).
Args:
-c
/--call-depth
sets the number of function calls deep within the current function we are allowed to emulate. (defaults to not emulating any function calls except hooked ones)
(0x1400015e0)> dis
0x1400015e0: __int64 __fastcall main();
-> 0x1400015e0: push rbp
0x1400015e1: push rbx
0x1400015e2: sub rsp, 68h
0x1400015e6: lea rbp, [rsp+60h]
0x1400015eb: call __main
0x1400015f0: lea rax, aThisIsSomeSamp; "This is some sample data to write to th"...
0x1400015f7: mov [rbp+10h+data], rax
0x1400015fb: mov [rsp+70h+hTemplateFile], 0; hTemplateFile
0x140001604: mov [rsp+70h+dwFlagsAndAttributes], 80h; dwFlagsAndAttributes
0x14000160c: mov [rsp+70h+dwCreationDisposition], 2; dwCreationDisposition
...
(0x1400015e0)> continue
(0x140001783)> dis
0x1400015e0: __int64 __fastcall main();
...
0x140001763: call _ZNSolsEPFRSoS_E; std::ostream::operator<<(std::ostream & (*)(std::ostream &))
0x140001768: mov rax, [rbp+10h+hFile]
0x14000176c: mov rcx, rax; _QWORD
0x14000176f: mov rax, cs:__IAT_start__
0x140001776: call rax ; __IAT_start__
0x140001778: mov eax, 0
0x14000177d: add rsp, 68h
0x140001781: pop rbx
0x140001782: pop rbp
-> 0x140001783: retn
0x1400016f5: lea rax, aErrorWritingTo; "Error writing to file: "
0x1400016fc: mov rdx, rax; a2
0x1400016ff: mov rax, cs:_refptr__ZSt4cout
0x140001706: mov rcx, rax; a1
0x140001709: call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc; std::operator<<<std::char_traits<char>>(std::ostream &,char const*)
0x14000170e: mov rbx, rax
0x140001711: mov rax, cs:__imp_GetLastError
0x140001718: call rax ; __imp_GetLastError
0x14000171a: mov edx, eax; a2
...
A given address or target variable can be provided to cause emulation to stop if the address is seen.
(0x140001783)> goto main
(0x1400015e0)> continue 0x14000173d
(0x14000173d)> dis
0x1400015e0: __int64 __fastcall main();
...
0x1400016d4: mov qword ptr [rsp+70h+dwCreationDisposition], 0; lpOverlapped
0x1400016dd: mov r9, rcx; lpNumberOfBytesWritten
0x1400016e0: mov rcx, rax; hFile
0x1400016e3: mov rax, cs:__imp_WriteFile
0x1400016ea: call rax ; __imp_WriteFile
0x1400016ec: test eax, eax
0x1400016ee: setz al
0x1400016f1: test al, al
0x1400016f3: jz short loc_14000173D
-> 0x14000173d: lea rax, aFileWroteSucce; "File wrote successfully."
0x140001744: mov rdx, rax; a2
0x140001747: mov rax, cs:_refptr__ZSt4cout
0x14000174e: mov rcx, rax; a1
0x140001751: call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc; std::operator<<<std::char_traits<char>>(std::ostream &,char const*)
0x140001756: mov rcx, rax; a1
0x140001759: mov rax, cs:_refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
0x140001760: mov rdx, rax; a2
0x140001763: call _ZNSolsEPFRSoS_E; std::ostream::operator<<(std::ostream & (*)(std::ostream &))
0x140001768: mov rax, [rbp+10h+hFile]
...
This can also be used to provide an instruction opcode to stop at as well.
(0x004014e0)> g sub_401000
(0x00401000)> dis
0x00401000: _BYTE *__cdecl sub_401000(_BYTE *a1, char a2);
-> 0x00401000: push ebp
0x00401001: mov ebp, esp
0x00401003: mov eax, [ebp+a1]
0x00401006: movsx ecx, byte ptr [eax]
0x00401009: test ecx, ecx
0x0040100b: jz short loc_401029
0x0040100d: movsx edx, [ebp+a2]
0x00401011: mov eax, [ebp+a1]
0x00401014: movsx ecx, byte ptr [eax]
0x00401017: xor ecx, edx
...
(0x00401000)> c movsx
(0x00401006)> dis
0x00401000: _BYTE *__cdecl sub_401000(_BYTE *a1, char a2);
0x00401000: push ebp
0x00401001: mov ebp, esp
0x00401003: mov eax, [ebp+a1]
-> 0x00401006: movsx ecx, byte ptr [eax]
0x00401009: test ecx, ecx
0x0040100b: jz short loc_401029
0x0040100d: movsx edx, [ebp+a2]
0x00401011: mov eax, [ebp+a1]
0x00401014: movsx ecx, byte ptr [eax]
0x00401017: xor ecx, edx
0x00401019: mov edx, [ebp+a1]
0x0040101c: mov [edx], cl
0x0040101e: mov eax, [ebp+a1]
...
Aliases: c
Sets the execution context to use an alternative branching path to reach the same destination. Prints the difference in branch pathing (displaying the first address of each basic block).
"forced" means the branching from the previous block was forced even though the emulated opcodes would not have dictated that direction.
(0x1400016bd)> goto 0x140001783
(0x140001783)> exec_history -i > first_path.txt
(0x140001783)> alternative
Branch Path:
0x1400015e0
+ 0x14000168e
- 0x140001643 (forced)
+ 0x1400016f5 (forced)
0x14000177d
(0x140001783)> alternative
Branch Path:
0x1400015e0
0x14000168e
- 0x1400016f5 (forced)
+ 0x14000173d
(0x140001783)> exec_history -i | diff first_path.txt -
23,39c23,61
< 0x140001643 lea rax, a2; "Error creating file: "
< 0x14000164a mov rdx, rax; a2
< 0x14000164d mov rax, cs:_refptr__ZSt4cerr
< 0x140001654 mov rcx, rax; a1
< 0x140001657 call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc; std::operator<<<std::char_traits<char>>(std::ostream &,char const*)
< 0x14000165c mov rbx, rax
< 0x14000165f mov rax, cs:__imp_GetLastError
< 0x140001666 call rax ; __imp_GetLastError
< 0x140001668 mov edx, eax; a2
< 0x14000166a mov rcx, rbx; a1
< 0x14000166d call _ZNSolsEm; std::ostream::operator<<(ulong)
< 0x140001672 mov rcx, rax; a1
< 0x140001675 mov rax, cs:_refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
< 0x14000167c mov rdx, rax; a2
< 0x14000167f call _ZNSolsEPFRSoS_E; std::ostream::operator<<(std::ostream & (*)(std::ostream &))
< 0x140001684 mov eax, 1
< 0x140001689 jmp loc_14000177D
---
> 0x14000168e lea rax, aFileCreatedOpe; "File created/opened successfully."
> 0x140001695 mov rdx, rax; a2
> 0x140001698 mov rax, cs:_refptr__ZSt4cout
> 0x14000169f mov rcx, rax; a1
> 0x1400016a2 call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc; std::operator<<<std::char_traits<char>>(std::ostream &,char const*)
> 0x1400016a7 mov rcx, rax; a1
> 0x1400016aa mov rax, cs:_refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
> 0x1400016b1 mov rdx, rax; a2
> 0x1400016b4 call _ZNSolsEPFRSoS_E; std::ostream::operator<<(std::ostream & (*)(std::ostream &))
> 0x1400016b9 mov rax, [rbp+10h+data]
> 0x1400016bd mov rcx, rax; Str
> 0x1400016c0 call strlen
> 0x1400016c5 mov r8d, eax; nNumberOfBytesToWrite
> 0x1400016c8 lea rcx, [rbp+10h+bytesWritten]
> 0x1400016cc mov rdx, [rbp+10h+data]; lpBuffer
> 0x1400016d0 mov rax, [rbp+10h+hFile]
> 0x1400016d4 mov qword ptr [rsp+70h+dwCreationDisposition], 0; lpOverlapped
> 0x1400016dd mov r9, rcx; lpNumberOfBytesWritten
> 0x1400016e0 mov rcx, rax; hFile
> 0x1400016e3 mov rax, cs:__imp_WriteFile
> 0x1400016ea call rax ; __imp_WriteFile
> 0x1400016ec test eax, eax
> 0x1400016ee setz al
> 0x1400016f1 test al, al
> 0x1400016f3 jz short loc_14000173D
> 0x14000173d lea rax, aFileWroteSucce; "File wrote successfully."
> 0x140001744 mov rdx, rax; a2
> 0x140001747 mov rax, cs:_refptr__ZSt4cout
> 0x14000174e mov rcx, rax; a1
> 0x140001751 call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc; std::operator<<<std::char_traits<char>>(std::ostream &,char const*)
> 0x140001756 mov rcx, rax; a1
> 0x140001759 mov rax, cs:_refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
> 0x140001760 mov rdx, rax; a2
> 0x140001763 call _ZNSolsEPFRSoS_E; std::ostream::operator<<(std::ostream & (*)(std::ostream &))
> 0x140001768 mov rax, [rbp+10h+hFile]
> 0x14000176c mov rcx, rax; _QWORD
> 0x14000176f mov rax, cs:__IAT_start__
> 0x140001776 call rax ; __IAT_start__
> 0x140001778 mov eax, 0
(0x140001783)>
Aliases: alt
Resets emulator, clearing all emulation history and restoring program counter back to entry point.
WARNING
This also clears undo history.
Undo the last executed emulation command.
(0x004014e0)> goto main
(0x00401150)> continue
(0x0040129f)> undo
(0x00401150)> undo
(0x004014e0)>
The following commands are used to display artifacts within the current emulation context.
Lists the interesting actions (API calls) that have taken place with the current context.
(0x140001783) > actions
address action handle attributes
----------- ----------- -------- ------------------------------------------------------
0x140001636 FileCreated 0x80 path='example.txt', mode='rw'
0x1400016ea FileWritten 0x80 data=b'This is some sample data to write to the file.'
0x140001776 FileClosed 0x80
Lists the current function arguments based on the current call instruction.
-n
/--num-args
directly sets the number of arguments to pull. (Useful for functions with variadic arguments)
(0x1400016ea)> instruction
call rax ; __imp_WriteFile
(0x1400016ea)> arguments
0x140009220: BOOL __stdcall __imp_WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
ordinal location type width name address value referenced data
--------- ----------- ------------ ------- ---------------------- ---------- ----------- ----------------------------------------------------
0 rcx handle 8 hFile 0x80
1 rdx lpcvoid 8 lpBuffer 0x140005000 b'This is some sample data to write to the file.\x..
2 r8d dword 4 nNumberOfBytesToWrite 0x2e
3 r9 lpdword 8 lpNumberOfBytesWritten 0x117f7d4 b'\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00..
4 stack[0x20] lpoverlapped 8 lpOverlapped 0x0117f7a8 0x0
An address or target variable can be provided to list what the arguments would be if the given function was called at the current context.
(0x140001756)> instruction
mov rcx, rax; a1
(0x140001756)> arguments WriteFile
0x140001798: BOOL __stdcall WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
ordinal location type width name address value referenced data
--------- ----------- ------------ ------- ---------------------- ---------- ----------- ----------------------------------------------------
0 rcx handle 8 hFile 0x140009310 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00..
1 rdx lpcvoid 8 lpBuffer 0x140005092 b'File wrote successfully.\x00\x01\x01\x01\x00\x00..
2 r8d dword 4 nNumberOfBytesToWrite 0x2e
3 r9 lpdword 8 lpNumberOfBytesWritten 0x117f7d4 b'.\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x0..
4 stack[0x20] lpoverlapped 8 lpOverlapped 0x0117f7a8 0x0
Aliases: arg
, args
Lists the observed files that were created during emulation.
(0x140001783) > files
handle path mode size closed deleted data
-------- ----------- ------ ------ -------- --------- -------------------------------------------------
0x80 example.txt rw 46 True False b'This is some sample data to write to the file.'
The contents of a file can be extracted by providing the handle as an argument. This data will be provided in raw bytes, so it is best to redirect the output to a file.
(0x140001783) > files 0x80 > example.txt
(0x140001783) > !cat example.txt
This is some sample data to write to the file.
Lists the currently allocated blocks of memory.
(0x140001756)> memory
start end size
----------- ----------- ------
0x0117f000 0x01180000 4096
0x140001000 0x140008000 28672
0x140009000 0x14000c000 12288
An address or target variable can be provided to read the memory at the given address.
Args:
-n
/--num
sets the number of bytes to read.--raw
writes out raw bytes instead of a hex dump.
(0x140001756)> memory 0x140005092 -n 30
140005092: 46 69 6C 65 20 77 72 6F 74 65 20 73 75 63 63 65 File wrote succe
1400050A2: 73 73 66 75 6C 6C 79 2E 00 01 01 01 00 00 ssfully.......
(0x140001756)> memory 0x140005092 -n 30 --raw > data.bin
Aliases: mem
Lists the high-level objects created within the current emulation context.
Lists the function arguments passed in as parameters for the current function.
(0x00401150)> parameters
0x00401150: int __cdecl _main(int argc, const char **argv, const char **envp);
ordinal location type width name address value referenced data
--------- ---------- ------------- ------- ------ ---------- ------- -----------------
0 stack[0x0] int 4 argc 0x0117f804 0x0
1 stack[0x4] const char ** 4 argv 0x0117f808 0x0
2 stack[0x8] const char ** 4 envp 0x0117f80c 0x0
Aliases: param
, params
Lists the current values of the registers.
Args:
-a
/--all
will also include registers with a zero value.
(0x140001756)> registers
family value
-------- -----------
rax 0x140009310
rcx 0x140009310
rdx 0x140005092
rbp 0x0117f7e8
rsp 0x0117f788
rip 0x140001756
r8 0x0000002e
r9 0x0117f7d4
eflags 0x00000044
The name of a register can be provided to display the value of that register.
(0x140001756)> registers ah
0x00000093
Aliases: reg
, regs
Lists the registry key objects created within the current context.
Lists the service objects created within the current context.
Outputs emulated stdout results.
(0x004011bc)> stdout
Hello World!
Test string with key 0x02
The quick brown fox jumps over the lazy dog.
Oak is strong and also gives shade.
Acid burns holes in wool cloth.
Lists all the variables (named data) encountered during emulation.
(0x00401174)> variables
address stack_offset name type size value
---------- -------------- --------------- ------------- ------ --------------------------------------------------
0x0040c000 aIdmmnVnsme char[13] 13 b'Hello World!\x00'
0x0040c010 aVgqvQvpkleUkvj char[26] 26 b'Test string with key 0x02\x00'
0x0040c02c aWkfRvjHAqltmEl char[45] 45 b'The quick brown fox j... over the lazy dog.\x00'
0x0040c05c aKeoMwWpvkjcEjE char[36] 36 b'Oak is strong and also gives shade.\x00'
0x0040c080 aDflaGpwkvMjiVL char[32] 32 b'Acid burns holes in wool cloth.\x00'
0x0040c0a0 aEgruGhbBiauCge char[35] 35 b'Cats and dogs each hate the other.\x00'
0x0040c0c4 aCv3gV3pargv3qf char[36] 36 b"Open the crate but don't break the g"
0x0040c0f0 aC char 1 84
0x0040c114 asc_40C114 char[11] 11 b'1234567890\x00'
0x0040c120 aQfbwfsqlFppb char[15] 15 b'CreateProcessA\x00'
0x0040c130 aTsudfs char[7] 7 b'StrCat\x00'
0x0040c138 byte_40C138 byte[8] 8 b'ASP.NET\x00'
0x0040c140 a5VTr4vTrv4tV char[21] 21 b'kdjsfjf0j24r0j240r2j0'
0x0040c15c aAkjdgbaKjgdbjk char[21] 21 b'32897412389471982470\x00'
0x0040c174 asc_40C174 char 1 84
0x0040c19c a4 char 1 67
0x0040c1c4 asc_40C1C4 char 1 84
0x0040c1f8 aLmfoghknlmgfoh char[78] 78 b'329087413289074981347...6598123056231895712\x00'
0x0040c248 Format char[4] 4 b'%s\n\x00'
0x0040c24c aS_0 char[4] 4 b'%s\n\x00'
0x0117f7ec -0x8 a1 byte * 4 4244037
0x0117f7f0 -0x4 a2 char 1 103
0x0117f804 0x10 argc int 4 0
0x0117f808 0x14 argv const char ** 4 0
0x0117f80c 0x18 envp const char ** 4 0
An address or variable name can be given to extract out data.
Args:
--raw
writes out raw bytes.
(0x00401174)> variables aIdmmnVnsme
b'Hello World!\x00'
(0x00401174)> variables aIdmmnVnsme --raw > data.bin
Aliases: var
, vars
Lists the starting addresses for each basic block within the branching path of the current execution context.
"forced" means the branching from the previous block was forced even though the emulated opcodes would not have dictated that direction.
Args:
-i
/--include-instructions
includes the instruction text for the head of each block.
(0x140001763)> branch_history -i
address forced instruction
----------- -------- -----------------------------------------------------------------
0x1400015e0 False push rbp
0x14000168e False lea rax, aFileCreatedOpe; "File created/opened successfully."
0x14000173d False lea rax, aFileWroteSucce; "File wrote successfully."
Aliases: bhist
Lists the history of called functions.
(0x140001783)> call_history
address function args
----------- ----------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
0x1400015eb _main
0x140001636 CreateFileA lpFileName=0x14000502f, dwDesiredAccess=0xc0000000, dwShareMode=0x3, lpSecurityAttributes=0x0, dwCreationDisposition=0x2, dwFlagsAndAttributes=0x80, hTemplateFile=0x0
0x1400016a2 operator<< param_1=0x10000000, param_2=0x140005058
0x1400016b4 operator<< this=0x10000000, param_1=0x1400017d8
0x1400016c0 strlen _Str=0x140005000
0x1400016ea WriteFile hFile=0x80, lpBuffer=0x140005000, nNumberOfBytesToWrite=0x2e, lpNumberOfBytesWritten=0x117f7d4, lpOverlapped=0x0
0x140001751 operator<< param_1=0x10000000, param_2=0x140005092
0x140001763 operator<< this=0x10000000, param_1=0x1400017d8
0x140001776 CloseHandle hObject=0x80
Aliases: chist
Prints a few lines of disassembly in both directions from the current instruction or given address/target variable.
(0x00401186)> disassembly
0x00401150: int __cdecl _main(int argc, const char **argv, const char **envp);
...
0x0040115d: push offset Format; "%s\n"
0x00401162: call _printf
0x00401167: add esp, 8
0x0040116a: push offset aVgqvQvpkleUkvj; "Vgqv\"qvpkle\"ukvj\"ig{\"2z20"
0x0040116f: push offset aS_0; "%s\n"
0x00401174: call _printf
0x00401179: add esp, 8
0x0040117c: push offset aWkfRvjHAqltmEl; "Wkf#rvj`h#aqltm#el{#ivnsp#lufq#wkf#obyz"...
0x00401181: push offset aS_1; "%s\n"
-> 0x00401186: call _printf
0x0040118b: add esp, 8
0x0040118e: push offset aKeoMwWpvkjcEjE; "Keo$mw$wpvkjc$ej`$ehwk$cmraw$wle`a*"
0x00401193: push offset aS_2; "%s\n"
0x00401198: call _printf
0x0040119d: add esp, 8
0x004011a0: push offset aDflaGpwkvMjiVL; "Dfla%gpwkv%mji`v%lk%rjji%fijqm+"
0x004011a5: push offset aS_3; "%s\n"
0x004011aa: call _printf
0x004011af: add esp, 8
...
(0x00401186)> disassembly op0
0x004012a0: int _printf(const char *const Format, DWORD a2, ...);
-> 0x004012a0: push 0Ch; a2
0x004012a2: push offset stru_40B3D0; a1
0x004012a7: call __SEH_prolog4
0x004012ac: xor eax, eax
0x004012ae: xor esi, esi
0x004012b0: cmp [ebp+Format], esi
0x004012b3: setnz al
0x004012b6: cmp eax, esi
0x004012b8: jnz short loc_4012D7
0x004012ba: call __errno
...
Aliases: dis
Generates a report containing the results of a number of different commands.
(0x140001763)> dump | head -n 20
# Rugosa Emulation Report
------------ ---------------------------------
File /home/ubuntu/dev/data/binary.exe
Disassembler IDA
Processor x86
Compiler Visual C++
Bit size 32
Endianness LE
Entry Point 0x004014e0
------------ ---------------------------------
se
## Disassembly
0x1400015e0: __int64 __fastcall main();
...
0x1400016f3: jz short loc_14000173D
0x14000173d: lea rax, aFileWroteSucce; "File wrote successfully."
0x140001744: mov rdx, rax; a2
0x140001747: mov rax, cs:_refptr__ZSt4cout
(0x140001763)> dump > report.txt
Lists the addresses of the instructions that have been emulated.
Args:
-i
/--include-instructions
includes instruction text for each address.
(0x140001763)> exec_history -i | head
address instruction
----------- ------------------------------------------------------------------------------------------------------------------------------------
0x1400015e0 push rbp
0x1400015e1 push rbx
0x1400015e2 sub rsp, 68h
0x1400015e6 lea rbp, [rsp+60h]
0x1400015eb call __main
0x1400015f0 lea rax, aThisIsSomeSamp; "This is some sample data to write to th"...
0x1400015f7 mov [rbp+10h+data], rax
0x1400015fb mov [rsp+70h+hTemplateFile], 0; hTemplateFile
Aliases: ehist
Prints the difference between the current stack pointer and the stack pointer at the beginning of the function.
(0x1400015e2)> spdiff
0x10
TIP
To have the current spdiff always displayed in the prompt, set the display_spdiff
setting.
(0x1400015e2)> set display_spdiff True
display_spdiff - was: False
now: True
(0x1400015e2 0x10)>
Since the shell tool is written using cmd2 we automatically benefit from some of the features provided by that library.
The shell can be provided some initial commands upon startup using a number of different methods.
- Provided at the end of the
rugosa
command.
rugosa binary.exe "set prompt_color red" "goto 0x1234" "dis"
- Provided as a file of newline delimited commands using
@
or-s
/--startup-script
rugosa binary.exe @mycommands.txt
- Set the
RUGOSA_STARTUP_SCRIPT
environment variable to a file path containing commands.
export RUGOSA_STARTUP_SCRIPT="~/mycommands.txt"
rugosa binary.exe
Setting up some startup commands can be helpful for things such as providing your own aliases, macros, or settings.
Adding quit
to the end of the commands will cause the shell not to spawn and return you back to the terminal.
Useful for repeatable or common one-off tasks.
$ echo "
# Emulates function at 0x401150 and returns emulated variables.
goto 0x401150
continue --call-depth 2
vars
quit
" > script.txt
$ rugosa binary.exe --nologo -s script.txt | head
address stack_offset name type size value
---------- -------------- ------------------------------------------- --------- ------ --------------------------------------------------
0x0040c000 s_Idmmn!Vnsme_0040c000 string 13 b'Hello World!\x00'
0x0040c010 s_Vgqv"qvpkle"ukvj"ig{"2z20_0040c010 string 26 b'Test string with key 0x02\x00'
0x0040c02c s_Wkf#rvj`h#aqltm#el{#ivnsp#lufq#w_0040c02c string 45 b'The quick brown fox j... over the lazy dog.\x00'
0x0040c05c s_Keo$mw$wpvkjc$ej`$ehwk$cmraw$wle_0040c05c string 36 b'Oak is strong and also gives shade.\x00'
0x0040c080 s_Dfla%gpwkv%mji`v%lk%rjji%fijqm+_0040c080 string 32 b'Acid burns holes in wool cloth.\x00'
0x0040c0a0 s_Egru&ghb&biau&cgen&ngrc&rnc&irnc_0040c0a0 string 35 b'Cats and dogs each hate the other.\x00'
0x0040c0c4 DAT_0040c0c4 undefined 1 79
0x0040c0f0 DAT_0040c0f0 undefined 1 84
$ rugosa binary.exe --nologo funcs quit | head
start end name
---------- ---------- ------------------------------
0x00401000 0x0040102b FUN_00401000
0x00401030 0x00401143 FUN_00401030
0x00401150 0x004012a0 FUN_00401150
0x004012a0 0x0040133c _printf
0x0040133c 0x0040134f FUN_0040133c
0x0040134f 0x00401365 __get_printf_count_output
0x00401365 0x0040138e _fast_error_exit
0x0040138e 0x004014e0 ___tmainCRTStartup
Along with the settings provided by cmd2, rugosa includes a few custom settings to control emulation and display settings.
These can be viewed and updated using the set
command.
(0x004014e0)> set
Name Value Description
==================================================================================================================
allow_style Terminal Allow ANSI text style sequences in output (valid values:
Always, Never, Terminal)
always_show_hint False Display tab completion hint even when completion suggestions
print
branch_tracking True When forcing emulation to go down the incorrect branch in
order to reach the desired end address, branch_tracking is
used to try to tweak the registers to make the branching
condition true. This can be helpful to ensure the rest of
the emulation is done correctly, however this will cause
emulation to run slower. So this option allows you to turn
it off when the feature is not necessary.
debug True Show full traceback on exception
display_instruction False Display current instruction in prompt
display_spdiff False Display the stack pointer diff in prompt
echo False Echo command issued into output
editor vim Program used by 'edit'
feedback_to_output False Include nonessentials in '|', '>' results
max_completion_items 50 Maximum number of CompletionItems to display during tab
completion
max_instructions 10000 Maximum number of instructions to allow when emulating loop
following code. This is used since it is possible that the
end instruction would never get reached.
max_undo_items 20 Maximum number of undo items to keep. Set to 0 to turn off
undo.
prompt_color green Color of prompt. 'reset' disables color
quiet False Don't print nonessential feedback
tablefmt simple Format for tables
timing False Report execution times
(0x004014e0)> set display_instruction True
display_instruction - was: False
now: True
(0x004014e0: call ___security_init_cookie)>
At any point, a python interpreter can be opened using the py
or ipy
command.
This allows for more advanced techniques that may not be possible with the exposed shell commands.
Upon opening up the interpreter, the following variables will be available in the namespace:
ctx
- The current ProcessorContext instance which holds all the emulation artifacts.emu
- The current Emulator instance which provides emulation control for creating new contexts.dis
- The dragodis Disassembler instance for accessing disassembly information.
(0x140001125)> py
Python 3.11.6 (main, Jan 16 2024, 16:42:17) [GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
Use `Ctrl-D` (Unix) / `Ctrl-Z` (Windows), `quit()`, `exit()` to exit.
Run CLI commands with: app("command ...")
>>> ctx.instruction
<rugosa.emulation.x86_64.instruction.x86_64Instruction object at 0x7f9ebca8ac90>
>>> ctx.operands
[<x86_64Operand 0x140001125:0 : rbp = 18349056 : width = 8>]
>>> ctx.execute(end=0x14000112D)
>>> exit()
Now exiting Python shell...
(0x14000112d)>
If you need to update the context instance, set the self.ctx
field for your new context to be applied after
exiting the interpreter.
>>> ctx, args = emu.get_function_arg_values(0x40103a)
>>> args
[4243456, 1]
>>> self.ctx = ctx
Most of the rugosa commands that accept an address as an argument can also accept an identifier instead.
The following are valid identifiers:
- integer or
0x
prefixed hex number - converts directly to an address. .
- The address of the current instruction.sp
- The current stack pointer. (alias torsp
)opX
- The referenced address or value within theX
position. (e.g.op0
for the first operand)argX
- The argument value within theX
position if currently on a call instruction. (e.g.arg0
for the first argument)- register name - The value within a register. (e.g.
edi
) - variable name - The address of a given variable seen in the variables command. (e.g.
s_Data
oraData
) - function name - The starting address of a given function name seen in the functions command. Extraneous underscores will be stripped. (e.g.
sub_401030
) - import name - The address of an import symbol. (e.g.
WriteFile
)