├── README.md ├── download_windows.sh ├── sample_app ├── MessageBoxApplication.cpp └── msg_app.zip ├── vm_record.py └── vm_replay.py /README.md: -------------------------------------------------------------------------------- 1 | # pandaMalbox 2 | This repo contains various scripts that can be used to work with the [PANDA](https://github.com/panda-re/panda) reverse engineering framework. The content is based on our blogpost with additional information [here](www.adalogics.com). 3 | 4 | ## Running the scripts 5 | 6 | ``` 7 | # Get this repo 8 | git clone https://github.com/AdaLogics/pandaIntro 9 | cd pandaIntro 10 | 11 | # Clone PANDA 12 | git clone https://github.com/panda-re/panda 13 | ./panda/panda/scripts/install_ubuntu.sh 14 | 15 | 16 | # Now install our stuff 17 | download_windows.sh 18 | 19 | ``` 20 | At this point we need to create a snapshot that is useful for analysis. To do this, please follow the instructions [here](www.adalogics.com). 21 | 22 | Then we can continue with creating a recording and replaying this recording. 23 | ``` 24 | # Make a recording of the sample 25 | cd sample_app 26 | unzip msg_app.zip 27 | cd .. 28 | 29 | python vm_record.py -sample sample_app/msg_app.exe 30 | 31 | python vm_replay.py -recording sample 32 | 33 | less panda_replay.stdout 34 | ... 35 | ``` 36 | -------------------------------------------------------------------------------- /download_windows.sh: -------------------------------------------------------------------------------- 1 | # Create a working directory 2 | mkdir sandbox_base 3 | cd sandbox_base 4 | 5 | # Download the disk image from Microsofts' website 6 | # (URL from https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/) 7 | wget https://az792536.vo.msecnd.net/vms/VMBuild_20150916/VirtualBox/IE8/IE8.Win7.VirtualBox.zip 8 | 9 | # Unzip the virtualbox zip 10 | unzip IE8.Win7.VirtualBox.zip 11 | 12 | # Untar the .ova 13 | tar -xvf IE8\ -\ Win7.ova 14 | 15 | # Create a qcow image from the .vmdk file. 16 | ## First install qemu utils 17 | sudo apt-get install qemu-utils 18 | 19 | ## Then create our image 20 | qemu-img convert -O qcow2 IE8\ -\ Win7-disk1.vmdk IE8_win7_disk1.qcow2 21 | chmod +x ./IE8_win7_disk1.qcow2 22 | 23 | ## Clean up some of the unnecessary files 24 | rm IE8\ -\ Win7-disk1.vmdk 25 | rm IE8\ -\ Win7.ova 26 | -------------------------------------------------------------------------------- /sample_app/MessageBoxApplication.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #pragma comment(lib, "User32.lib") 12 | 13 | int DisplayResourceNAMessageBox() 14 | { 15 | TCHAR szExeFileName[0x100]; 16 | GetModuleFileName(NULL, szExeFileName, 0x100); 17 | 18 | int msgboxID = MessageBox( 19 | NULL, 20 | 21 | (LPCWSTR)szExeFileName, 22 | (LPCWSTR)L"Currently executing inside", 23 | MB_OK 24 | ); 25 | 26 | return msgboxID; 27 | } 28 | 29 | int main() 30 | { 31 | std::cout << "Hello World!\n"; 32 | DisplayResourceNAMessageBox(); 33 | } -------------------------------------------------------------------------------- /sample_app/msg_app.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaLogics/pandaMalbox/4995f4c03644063dd5d1ca922d842b4d1c3ffed1/sample_app/msg_app.zip -------------------------------------------------------------------------------- /vm_record.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import time 4 | import subprocess 5 | import argparse 6 | import string 7 | import shutil 8 | 9 | # Configs 10 | PANDA_BASE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "panda") 11 | PANDA_x86 = os.path.join(PANDA_BASE, "build", "i386-softmmu", "qemu-system-i386") 12 | IMG_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "sandbox_base/IE8_win7_disk1.qcow2") 13 | 14 | PANDA_flags = [ 15 | "-monitor", "stdio", 16 | "-show-cursor", 17 | "-m", "8192", 18 | "-loadvm", "1", 19 | IMG_PATH 20 | ] 21 | TIME_TO_EXECUTE = 20 22 | 23 | def log_info(msg): 24 | print("[+] %s"%(msg)) 25 | 26 | def log_exit(msg): 27 | print("[-] %s"%(msg)) 28 | exit(0) 29 | 30 | def guest_type(s, p): 31 | 32 | keymap = { 33 | '-': 'minus', 34 | '=': 'equal', 35 | '[': 'bracket_left', 36 | ']': 'bracket_right', 37 | ';': 'semicolon', 38 | '\'': 'apostrophe', 39 | '\\': 'backslash', 40 | ',': 'comma', 41 | '.': 'dot', 42 | '/': 'slash', 43 | '*': 'asterisk', 44 | ' ': 'spc', 45 | '_': 'shift-minus', 46 | '+': 'shift-equal', 47 | '{': 'shift-bracket_left', 48 | '}': 'shift-bracket_right', 49 | ':': 'shift-semicolon', 50 | '"': 'shift-apostrophe', 51 | '|': 'shift-backslash', 52 | '<': 'shift-comma', 53 | '>': 'shift-dot', 54 | '?': 'shift-slash', 55 | '\n': 'ret', 56 | } 57 | 58 | for c in s: 59 | if c in string.ascii_uppercase: 60 | key = 'shift-' + c.lower() 61 | else: 62 | key = keymap.get(c, c) 63 | 64 | p.stdin.write("sendkey %s\n"%(key)) 65 | time.sleep(.5) 66 | 67 | def record_execution(sample, recording_time): 68 | ''' 69 | 70 | ''' 71 | log_info("Recording execution %s"%(sample)) 72 | log_info("Recording for %d seconds"%(recording_time)) 73 | 74 | 75 | # Create new temporary sample 76 | new_sample = "sample" 77 | shutil.copy(sample, new_sample) 78 | 79 | 80 | # Create an ISO file of the sample file 81 | cmd = [] 82 | cmd.append("/usr/bin/genisoimage") 83 | cmd.append("-iso-level") 84 | cmd.append("4") 85 | cmd.append("-l") 86 | cmd.append("-R") 87 | cmd.append("-J") 88 | cmd.append("-o") 89 | cmd.append("sample.iso") 90 | cmd.append(new_sample) 91 | 92 | try: 93 | subprocess.check_call(cmd) 94 | log_info("Made an iso file for the sample") 95 | except Exception: 96 | print(traceback.format_exc()) 97 | print(sys.exc_info()[0]) 98 | log_exit("Could not make any iso file for the sample") 99 | 100 | # Launch PANDA 101 | cmd = [] 102 | cmd.append(PANDA_x86) 103 | for flag in PANDA_flags: 104 | cmd.append(flag) 105 | 106 | panda_stdout_path = "panda.stdout" 107 | panda_stderr_path = "panda.stderr" 108 | panda_stdout = open(panda_stdout_path, 'w+') 109 | panda_stderr = open(panda_stderr_path, 'w+') 110 | 111 | #log_info("Executing command: %s"%(" ".join(cmd))) 112 | p = subprocess.Popen(cmd, 113 | stdin = subprocess.PIPE, 114 | stdout = panda_stdout, 115 | stderr = panda_stderr) 116 | 117 | p.stdin.write("MARK\n") 118 | 119 | # Check whenever the virtual machine is ready for us to interact with it. 120 | f_out = open(panda_stdout_path, "r") 121 | while True: 122 | content = f_out.read() 123 | if "MARK" in content: 124 | log_info("VM started") 125 | break 126 | f_out.seek(0) 127 | time.sleep(0.5) 128 | 129 | # Sleep for 1 second 130 | time.sleep(1) 131 | 132 | # Configure QEMU so the sample.iso file is mounted in the cdrom. 133 | p.stdin.write("change ide1-cd0 sample.iso\n") 134 | 135 | # Sleep for 3 seconds 136 | time.sleep(5) 137 | 138 | # Because the cd-rom was mounted, a window in the guest was opened, 139 | # close this window now by sending the escape key to the guest. 140 | p.stdin.write("sendkey esc\n") 141 | 142 | # Write the command in the guest command line interface to 143 | # copy the sample in the cd-rom drive onto the guest desktop. 144 | copy_cmd = " copy D:\\sample C:\\Users\\IEUser\\Desktop\\sample.exe\n" 145 | guest_type(copy_cmd, p) 146 | 147 | # Sleep for 5 seconds to make sure the guest finished it's tasks. 148 | time.sleep(5) 149 | 150 | # Start writing the command that will execute the sample inside 151 | # the guest machine. Notice that we don't actually execute the command 152 | # as there is no \n at the end of the line. We do this because we want to 153 | # start recording the guest execution before the application executes 154 | start_cmd = "start C:\\Users\\IEUser\\Desktop\\sample.exe" 155 | guest_type(start_cmd, p) 156 | 157 | # Now begin recording before we launch the above command 158 | p.stdin.write("begin_record sample\n") 159 | 160 | # Now send the final \n that will launch the execution command. 161 | guest_type("\n", p) 162 | 163 | log_info("Started recording and executed the sample in the guest machine") 164 | 165 | 166 | log_info("Recording for: %d seconds"%(TIME_TO_EXECUTE)) 167 | time.sleep(TIME_TO_EXECUTE) 168 | 169 | # End the record 170 | p.stdin.write("end_record\n") 171 | 172 | # Exit the VM 173 | p.stdin.write("q\n") 174 | 175 | log_info("Recording is over, shutting the VM down") 176 | p.stdin.write("q\n") 177 | time.sleep(3) 178 | 179 | while True: 180 | poll = p.poll() 181 | if poll == None: 182 | time.sleep(1) 183 | else: 184 | log_info("VM is shut down") 185 | break 186 | 187 | log_info("Finished recording the sample execution") 188 | 189 | if __name__ == "__main__": 190 | parser = argparse.ArgumentParser() 191 | 192 | parser.add_argument( 193 | "-sample", 194 | help = "The sample to executed", 195 | required = True) 196 | 197 | parser.add_argument( 198 | "-time", 199 | help = "The number of seconds to record an execution", 200 | type = int, 201 | default = 25) 202 | 203 | args = parser.parse_args(args = sys.argv[1:]) 204 | 205 | record_execution(args.sample, args.time) 206 | -------------------------------------------------------------------------------- /vm_replay.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import subprocess 4 | import argparse 5 | import time 6 | 7 | # Configs 8 | PANDA_BASE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "panda") 9 | PANDA_x86 = os.path.join(PANDA_BASE, "build", "i386-softmmu", "qemu-system-i386") 10 | IMG_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "sandbox_base/IE8_win7_disk1.qcow2") 11 | 12 | PANDA_flags = [ 13 | "-monitor", "stdio", 14 | "-show-cursor", 15 | "-m", "8192", 16 | ] 17 | 18 | # The PADNA plugins we would like to use 19 | PANDA_plugins = [ 20 | "-panda osi -os windows-32-7 -panda win7x86intro -panda osi_test" 21 | ] 22 | 23 | def log_info(msg): 24 | print("[+] %s"%(msg)) 25 | 26 | def log_exit(msg): 27 | print("[-] %s"%(msg)) 28 | exit(0) 29 | 30 | def replay_recording(snapshot_name): 31 | ''' 32 | Replays a recording 33 | ''' 34 | 35 | log_info("Replaying %s"%(snapshot_name)) 36 | 37 | # Launch PANDA 38 | cmd = [] 39 | cmd.append(PANDA_x86) 40 | cmd.append("-replay") 41 | cmd.append(snapshot_name) 42 | 43 | for flag in PANDA_flags: 44 | cmd.append(flag) 45 | 46 | for plugin_cmdline in PANDA_plugins: 47 | cmd.append(plugin_cmdline) 48 | 49 | # Output files 50 | panda_stdout_path = "replay_panda.stdout" 51 | panda_stderr_path = "replay_panda.stderr" 52 | panda_stdout = open(panda_stdout_path, 'w+') 53 | panda_stderr = open(panda_stderr_path, 'w+') 54 | 55 | log_info("Launching replay %s"%(" ".join(cmd))) 56 | try: 57 | p = subprocess.Popen( 58 | " ".join(cmd), 59 | shell=True, 60 | stdout = panda_stdout, 61 | stderr = panda_stderr, 62 | preexec_fn = os.setsid) 63 | except: 64 | log_exit("Could not complete replay") 65 | 66 | log_info("Replay launched") 67 | 68 | while True: 69 | poll = p.poll() 70 | if poll == None: 71 | time.sleep(1) 72 | else: 73 | log_info("Replaying finished") 74 | break 75 | 76 | log_info("Analysis process finished, exiting") 77 | 78 | 79 | if __name__ == "__main__": 80 | parser = argparse.ArgumentParser() 81 | 82 | parser.add_argument( 83 | "-recording", 84 | help = "The name of the snapshot to replay", 85 | required = True) 86 | 87 | args = parser.parse_args(args = sys.argv[1:]) 88 | replay_recording(args.recording) 89 | --------------------------------------------------------------------------------