1 00:00:25,080 --> 00:00:26,440 Okay, hello everyone. 2 00:00:26,440 --> 00:00:31,140 My name is Paramount Kid and I welcome you to Reversing with Dynamic Data Resolver. 3 00:00:31,140 --> 00:00:41,380 If you are not already in the Discord chat, please go to blueteamvillage.org, click on the Discord channel link, and I would like you to give a warm welcome to Mr. 4 00:00:41,380 --> 00:00:45,660 Holger and let's start with the talk. 5 00:00:48,060 --> 00:00:54,160 Hi and welcome to my presentation, Reversing with Dynamic Data Resolver Best Practices. 6 00:00:54,560 --> 00:00:56,060 My name is Holger Unterwink. 7 00:00:56,060 --> 00:01:03,140 I'm a security researcher at Cisco Talos and I'm mainly focused on malware research, threat hunting, and tool development. 8 00:01:03,480 --> 00:01:08,140 If you want to follow me on Twitter, you can find me at hunterbr72. 9 00:01:08,420 --> 00:01:30,560 I'm the author of DDR and I will guide you through the different features of DDR today, the installation process, and I will show you some of the best practices, how to use the tool, and some of the special cases and caveats which you can see later on in the demos where you might can run into. 10 00:01:32,920 --> 00:01:35,680 So what is Dynamic Data Resolver? 11 00:01:35,680 --> 00:01:39,260 First of all, Dynamic Data Resolver is an instrumentation tool. 12 00:01:39,260 --> 00:01:54,800 It is instrumenting the binary so that you can trace all the instructions the binary is executing and it is collecting all kinds of data from strings to register values, memory locations, etc. 13 00:01:54,800 --> 00:01:55,580 etc. 14 00:01:55,880 --> 00:02:09,480 It comes with an IDA plugin which is controlling the backend so you can easily handle everything from this IDA plugin and you don't need to use the command line tools. 15 00:02:09,480 --> 00:02:14,400 You can and I will talk about that later on. 16 00:02:15,680 --> 00:02:18,880 DDR comes with an client-server architecture. 17 00:02:18,940 --> 00:02:34,960 So you have the DDR server which is running on the malware PC side, so the PC where you are executing malware, and you have the IDA plugin which is running inside of IDA on the analyst PC. 18 00:02:34,960 --> 00:02:38,880 It is highly recommended to separate these two machines. 19 00:02:38,880 --> 00:02:46,900 In theory, you can run all of that on one machine, but keep in mind that you are executing the malware at the end. 20 00:02:46,900 --> 00:02:56,200 So the malware really runs on that machine and you might not want to infect your machine where you have your IDA installation on. 21 00:02:56,760 --> 00:03:00,120 It'll be infected with malware. 22 00:03:02,940 --> 00:03:06,120 So what can I do with DDR? 23 00:03:07,140 --> 00:03:15,940 DDR was mainly built to resolve dynamic values and this is why I've called it a dynamic data resolver. 24 00:03:15,940 --> 00:03:18,680 But it comes with all kinds of other features. 25 00:03:18,860 --> 00:03:23,260 But for now, let's keep with the data resolving option you have in DDR. 26 00:03:23,340 --> 00:03:27,640 You have the option to resolve certain register values, for example. 27 00:03:27,640 --> 00:03:38,120 So if you want to know the absolute value of EDI or EBX or EAX, you can just do that with one click. 28 00:03:38,360 --> 00:03:45,080 You can also get the pointer to the memory this value is pointing to, or even the pointer pointer. 29 00:03:45,360 --> 00:03:58,440 And DDR also tries to detect if the address which is stored in a certain register, if that one points to a certain API call like virtual protect. 30 00:03:58,660 --> 00:04:09,100 And if that is the case, it will also resolve the API call so you can see the human readable name of the function call. 31 00:04:12,450 --> 00:04:22,990 After you have run a trace and DDR has all the instruction traced, you can highlight the instructions with a color. 32 00:04:23,010 --> 00:04:29,090 You can just highlight them depending on how many times they were executed. 33 00:04:29,150 --> 00:04:39,150 So you get a pretty quick overview about which basic blocks were executed by the program and how often these basic blocks were executed by the program. 34 00:04:39,190 --> 00:04:55,130 As you can see here on the slide, if you see a color which is a more warmer color, like red or purple, you know that this basic block or these instructions were executed many times. 35 00:04:55,230 --> 00:04:59,730 So it is likely that it is maybe a decoding routine or something like that. 36 00:04:59,730 --> 00:05:09,070 So that already gives you a good clue about what the sample is doing and what parts of the sample are executed and what other parts are maybe not executed. 37 00:05:10,330 --> 00:05:18,030 You can also get a table of all the API calls the sample has executed. 38 00:05:18,370 --> 00:05:21,210 So you can search through this list. 39 00:05:21,210 --> 00:05:26,550 You can search for certain API calls like a virtual alloc or something like that. 40 00:05:26,550 --> 00:05:35,750 And then you can do a double click on the line and you are jumping to the disassembly code where this API call was called. 41 00:05:36,490 --> 00:05:38,850 The same applies for strings. 42 00:05:38,850 --> 00:05:43,170 As I mentioned earlier, DDR tries to collect all the strings at runtime. 43 00:05:43,410 --> 00:05:46,790 And it is filling this table with these strings. 44 00:05:46,790 --> 00:05:49,090 And the table is again searchable. 45 00:05:49,090 --> 00:06:06,890 So you can look for certain interesting strings like PE, for example, if you're looking for a PE header, and then double click on this line and check out in the disassembly what's going on where this was used. 46 00:06:06,910 --> 00:06:10,530 And we will see all of that later on in the live demo. 47 00:06:13,580 --> 00:06:19,100 Another neat feature of DDR is that there's a smart way to dump buffers at runtime. 48 00:06:20,020 --> 00:06:33,780 So all you have to hand over to DDR is the size of the buffer, the address of the buffer, and when or where you want to dump the buffer. 49 00:06:33,900 --> 00:06:36,980 And we will also see that later on. 50 00:06:37,260 --> 00:06:44,900 For example, you just have to mark the operands in the disassembly which are storing these informations. 51 00:06:44,900 --> 00:06:49,960 The size, the address, and at the end where you want to dump the buffer. 52 00:06:53,600 --> 00:06:57,660 Unfortunately, often malware comes with anti-analyzing features. 53 00:06:57,660 --> 00:07:02,520 And it is not executed like it would be executed on a normal PC. 54 00:07:02,540 --> 00:07:04,920 If you're running it in a VMware, for example. 55 00:07:05,480 --> 00:07:10,360 So DDR comes with an option to patch the sample at runtime. 56 00:07:10,520 --> 00:07:13,920 So for example, you can knock out certain instructions. 57 00:07:14,020 --> 00:07:19,480 Or you can toggle the E-flag and manipulate the execution flow. 58 00:07:19,480 --> 00:07:28,420 So if there's a conditional branch, you can just toggle the E-flag and the conditional branch will do the exact opposite. 59 00:07:28,640 --> 00:07:32,220 But again, we will see that later on also in the demo. 60 00:07:32,540 --> 00:07:38,100 And last but not least, you also have the option to completely skip certain functions. 61 00:07:38,380 --> 00:07:43,700 You can just mark a function, skip it, and return a fake return value. 62 00:07:44,020 --> 00:08:05,500 So if you have, for example, a certain function in your malware sample which is checking for virtual machines or for anti-debugging stuff, you can just skip the function and return the value which is telling the sample that it is not getting debugged or that it's not running on a virtual machine. 63 00:08:05,500 --> 00:08:08,920 But again, we will see that later on in the demo. 64 00:08:11,220 --> 00:08:23,720 If IDA and DDR is not enough for you to analyze the sample, you can also create an x64 debug script which is automatically executing the sample. 65 00:08:23,720 --> 00:08:40,240 So it automatically loads the sample into x64 debug and it is automatically breaking at that address which you have highlighted in IDA when you have picked this menu point. 66 00:08:40,500 --> 00:08:52,480 If you don't like x64 debug, you also have the option to create a new executable of the binary with an endless loop at the marked address. 67 00:08:52,480 --> 00:09:08,420 So you can mark a certain location or certain address inside of IDA, pick this menu option, and then a new binary is generated which has an endless loop patched at that location. 68 00:09:08,420 --> 00:09:20,080 So you can start the binary, it starts to loop endlessly, and you can attach your favorite debugger to it, restore the bytes, and proceed debugging it. 69 00:09:22,620 --> 00:09:28,500 Okay, that should be enough for a quick overview about what you can do with DDR. 70 00:09:28,580 --> 00:09:34,680 In the upcoming demo, we will see all these features in detail again. 71 00:09:35,120 --> 00:09:38,200 So let's start with the installation. 72 00:09:38,920 --> 00:09:41,920 Of course, first of all, you have to download DDR. 73 00:09:41,920 --> 00:09:45,300 You can get it from its repository on GitHub. 74 00:09:45,560 --> 00:09:50,780 And once you have downloaded it, it comes with an installation script. 75 00:09:50,840 --> 00:09:59,480 And pretty much all you have to do is to execute this installation script, and it will guide you through the installation process. 76 00:10:00,060 --> 00:10:04,360 Again, we will see that later on in the next demo. 77 00:10:05,440 --> 00:10:11,900 If you want to stay up to date with the latest versions of DDR, you can follow me on Twitter. 78 00:10:11,900 --> 00:10:23,080 And every time I'm changing, fixing, or fixing anything, or releasing new stuff for DDR, I will announce that on my Twitter account. 79 00:10:23,420 --> 00:10:46,860 If this presentation is not enough for the information you are looking for, you can also find a very detailed blog post about DDR, which I've released end of May on our blog, which is also describing the different steps, the different features, and the best practices, 80 00:10:47,340 --> 00:10:53,000 and the caveats which you have to be aware of when you are working with DDR. 81 00:10:56,360 --> 00:11:00,160 DDR has a client-server architecture. 82 00:11:00,460 --> 00:11:06,020 Keep in mind that DDR is instrumenting the binary. 83 00:11:06,020 --> 00:11:10,060 So the binary is getting executed at the end. 84 00:11:10,160 --> 00:11:30,240 So it is highly recommended to split the analyzing part and the execution part, so that you have an analyst PC where your IDA is running on, including the plug-in, and a dedicated malware PC where you are executing the malware sample and analyzing the malware sample. 85 00:11:30,260 --> 00:11:55,200 The DDR server is controlling the backend of DDR, which is implemented using the DynamoRIO framework, and that one is at the end executing the sample, instrumenting the sample, and collecting all the data, which is then transferred back to the IDA plug-in. 86 00:11:55,260 --> 00:11:59,300 But we will also see that later on in a demo. 87 00:12:02,770 --> 00:12:06,010 Okay, so enough theory. 88 00:12:06,090 --> 00:12:10,870 Let's have a look how that looks in the real world. 89 00:12:12,570 --> 00:12:14,870 Installing DDR is pretty straightforward. 90 00:12:14,870 --> 00:12:24,190 All you have to do is to execute the ddr-installer.py script, and it is solving all the dependencies for you. 91 00:12:24,890 --> 00:12:36,050 After it has downloaded all the dependencies, it will ask you a couple of questions about the IDA installation directory, the IP address it is supposed to listen on, etc. 92 00:12:36,050 --> 00:12:36,790 etc. 93 00:12:36,910 --> 00:12:46,990 And after you have done that, you can start a local HTTP server, or in other words, the script is starting an HTTP server for you. 94 00:12:46,990 --> 00:13:01,250 And then you can move over to the IDA machine and access this HTTP server and download the DDR IDA plug-in site of the installation. 95 00:13:01,710 --> 00:13:09,110 Then you unzip the file and copy over the content to the traditional IDA plug-in directory. 96 00:13:09,110 --> 00:13:13,490 That will change in the next release, which is coming out very soon. 97 00:13:13,490 --> 00:13:18,210 And we will move over to the IDA user plug-in directory. 98 00:13:18,710 --> 00:13:23,630 So that has the advantage that you will not need any administrative rights anymore. 99 00:13:25,070 --> 00:13:31,250 Once you have done that, you need to figure out which Python version your IDA installation is using. 100 00:13:31,250 --> 00:13:42,410 And then you need to install two dependencies for this Python version, the requests library and the pfile library. 101 00:13:42,790 --> 00:13:45,070 And with this, you are ready to go. 102 00:13:45,070 --> 00:13:52,130 And you can move over to the server side again and start the DDR server. 103 00:13:52,690 --> 00:14:05,330 Okay, so after we've seen how the installation works, I can give you now a quick walkthrough of the different DDR features, which I've mentioned earlier. 104 00:14:06,410 --> 00:14:13,730 Okay, for this end, we have a dedicated analyst PC where IDA is running on, including the plug-in. 105 00:14:13,730 --> 00:14:22,190 And we have a dedicated machine where we are executing the malware on and where DDR server is running on. 106 00:14:22,190 --> 00:14:26,170 So let's move to this malware machine. 107 00:14:28,630 --> 00:14:35,830 Once on the malware machine side, we are starting the DDR server via the DDR server Python script. 108 00:14:36,490 --> 00:14:50,410 And when we are starting it, there's a little hind that you have to be aware of, that there is a caveat with Windows command prompt and Python scripts. 109 00:14:50,410 --> 00:14:57,070 If you're marking any text in the output window, you are freezing the Python application. 110 00:14:57,150 --> 00:15:05,330 So that means that if the plug-in would try to talk to the server now, you would run into a timeout. 111 00:15:05,330 --> 00:15:17,450 If that happens, you just need to hit escape a couple of times or just do a ctrl z and restart the server if you like. 112 00:15:23,310 --> 00:15:25,830 Okay, so let's move over to IDA. 113 00:15:30,850 --> 00:15:36,290 The first thing you usually want to do is you want to run a trace. 114 00:15:36,290 --> 00:15:44,330 A trace is filling all the internal data structures inside of DDR which are necessary for most of the other features. 115 00:15:44,770 --> 00:15:49,550 And you have two options, either to run a light trace or a full trace. 116 00:15:49,750 --> 00:15:56,070 A full trace is a trace which is collecting as much information as possible per instruction. 117 00:15:56,250 --> 00:16:02,530 So for example, it is saving all the register values for every single instruction. 118 00:16:02,670 --> 00:16:19,670 A light trace is only collecting a subset for these informations, but enough informations that you can have a look at the API calls, for example, or at the strings which were traced, or to get a source operand. 119 00:16:19,870 --> 00:16:28,130 And a light trace is usually something which I'm running when I start to analyze the sample. 120 00:16:28,130 --> 00:16:39,170 And if I just want to get an overview, if I just want to highlight the traced instructions, for example, or if I just want to see the API calls, then the light trace is good enough. 121 00:16:39,170 --> 00:16:51,610 Later on, when I'm analyzing a crypto algorithm, for example, and I need more informations, for example, all the registers, then I'm running a full trace. 122 00:16:51,610 --> 00:17:00,510 But I'm only running a full trace for a small address range or for a few basic blocks, for example. 123 00:17:00,510 --> 00:17:06,870 Because this is really time consuming and it is also consuming a lot of memory. 124 00:17:06,990 --> 00:17:15,110 So you usually want to limit the amount of instructions which you are instrumenting within full trace. 125 00:17:17,130 --> 00:17:19,390 Okay, enough about traces. 126 00:17:19,390 --> 00:17:25,750 Let's run the light trace and check how that looks like on the DDR server side. 127 00:17:26,710 --> 00:17:33,970 So the sample is executed and the dialog box which you have just seen just belongs to the sample code. 128 00:17:33,970 --> 00:17:36,490 It doesn't have anything to do with DDR. 129 00:17:36,530 --> 00:17:38,390 Don't be confused by that. 130 00:17:38,390 --> 00:17:50,690 Once the analysis is done, you can see that the trace log file is written to the same directory where the original sample is located. 131 00:17:51,330 --> 00:18:02,050 And you can also see that the temporary trace files were deleted based on a server command and then transferred over to the IDA plugin. 132 00:18:02,050 --> 00:18:04,650 So now we can switch back to IDA. 133 00:18:04,650 --> 00:18:09,030 And we also see this method can switch back to IDA. 134 00:18:09,030 --> 00:18:16,210 And we also see this message inside of IDA that the light trace was done successfully. 135 00:18:18,070 --> 00:18:23,590 So this means that DDR now has all the information it needs. 136 00:18:23,590 --> 00:18:36,990 And we can execute other features like highlighted traced instruction, which is giving us an overview about which basic blocks were executed or which instructions were executed. 137 00:18:42,700 --> 00:18:45,820 Okay, so let's move to the next feature. 138 00:18:45,820 --> 00:18:48,580 You can nop out instructions at runtime. 139 00:18:49,580 --> 00:19:03,560 So if you have certain instructions which you want to get rid of, like the dialog box which we have seen earlier, you can just mark these instructions and you go to the patch menu in DDR. 140 00:19:04,060 --> 00:19:16,320 And then the next time you execute the sample, so for example you run a new trace, then these instructions are nopped out, they're not getting executed anymore. 141 00:19:16,320 --> 00:19:29,960 And you can see here that it is responding much faster because we didn't have the pop-up of the dialog box and the sample immediately proceeded with execution. 142 00:19:33,130 --> 00:19:41,330 Okay, the next feature which I would like to show you is how you can use the dynamic values which were collected by the trace. 143 00:19:41,650 --> 00:19:44,130 Now first we are doing a trace again. 144 00:19:44,130 --> 00:19:48,430 This time we are just doing a trace over a couple of instructions. 145 00:19:48,570 --> 00:19:51,690 Now you're picking full trace for marked address range. 146 00:19:52,110 --> 00:20:00,310 And once this is done, we have all the values from these instructions inside of the database. 147 00:20:00,410 --> 00:20:08,310 So we can just go to get value for source operand and we are getting the value for RAX in this case. 148 00:20:11,140 --> 00:20:22,700 Or we can just get the values from memory pointers like you can see here, or all kinds of other information DDR has collected. 149 00:20:49,100 --> 00:20:55,660 The next nice feature is that you can collect all the strings and API calls at runtime. 150 00:20:56,320 --> 00:21:02,500 You can show both of them via tables where the DDR menu. 151 00:21:02,500 --> 00:21:09,900 So if we are looking at the strings, for example, this is a list of all the strings which we have collected at runtime. 152 00:21:09,980 --> 00:21:14,920 And of course you can also search for something in there, like PE for example. 153 00:21:14,920 --> 00:21:23,000 And if you're double clicking on the line, then you're jumping to the line in the assembly where it is used. 154 00:21:24,640 --> 00:21:29,620 You can also have a look at the API calls which were executed at runtime. 155 00:21:29,880 --> 00:21:32,660 And again, the same applies like for strings. 156 00:21:32,660 --> 00:21:36,280 You can search for something and double click on it. 157 00:21:36,280 --> 00:21:41,820 And then you see where it is used inside of the code. 158 00:21:43,880 --> 00:21:49,660 You have seen earlier that you can manipulate the code flow by nopping out instructions. 159 00:21:49,960 --> 00:21:55,240 But there are also other options inside of DDR which are manipulating the code flow. 160 00:21:55,240 --> 00:22:00,840 The next one which I would like to talk about is the option to toggle the E-flags. 161 00:22:00,840 --> 00:22:11,200 So for example, if we have a code like this, where we have a conditional jump and a comparison before, then we can toggle the E-flag at the jump. 162 00:22:11,200 --> 00:22:15,960 In this case, you have to know that EAX can never be bigger than 5. 163 00:22:15,960 --> 00:22:21,680 So at least in theory, this jump should always be taken in this code. 164 00:22:21,680 --> 00:22:27,500 And the program should print out main A is not greater than 5. 165 00:22:28,560 --> 00:22:38,360 If we want to manipulate that, we can just mark the GLAE instruction, do a right click, and go to the patch menu inside of DDR. 166 00:22:43,270 --> 00:22:46,950 Inside of the patch menu, we pick a toggle E-flag. 167 00:22:46,950 --> 00:22:49,750 In this case, we have to toggle the SF-flag. 168 00:22:50,370 --> 00:22:56,330 And once this is done, we can now just run the sample if we want. 169 00:22:56,570 --> 00:23:07,630 So for example, again over the patch menu, if we pick that one, then the sample is just getting executed. 170 00:23:07,630 --> 00:23:16,570 But we could also use any other feature of DDR, running a trace or doing a dump, which we will see later on. 171 00:23:16,570 --> 00:23:24,150 All these patches which I have applied will work for all the DDR features. 172 00:23:24,470 --> 00:23:34,750 Once we executed it, then we can move over to the DDR side and check the output of the file. 173 00:23:34,750 --> 00:23:36,690 Sorry, of the executable. 174 00:23:37,890 --> 00:23:48,590 So here you can see that the patch worked, and the program printed out A is greater than 5, and this should never happen. 175 00:23:50,940 --> 00:23:55,760 The last option you have is you can skip functions at runtime. 176 00:23:56,320 --> 00:24:09,400 So for example, if we have my function 1 here in this case, maybe something which is doing some anti-analyzing, anti-debugging stuff, you can just skip it and you can fake the return value. 177 00:24:09,400 --> 00:24:24,640 You're just marking the first instruction in the function, and you are going again to the patch menu, skip function at marked address at runtime, and you hand over the faked return value, and that's it. 178 00:24:28,930 --> 00:24:32,350 Now you can execute the sample again. 179 00:24:33,970 --> 00:24:55,270 And if we are moving over to the DDR server side, we see that the sample is getting executed, and in the output of the sample, we see that the my function 1 output is gone, because the my function 1 is not executed anymore. 180 00:24:55,830 --> 00:25:03,450 And another main function of DDR is that you can dump buffers at runtime. 181 00:25:03,530 --> 00:25:05,930 And you can do that in a smart way. 182 00:25:06,190 --> 00:25:12,430 Later on, this string will be copied into this buffer, which we are going to dump. 183 00:25:12,630 --> 00:25:14,730 So remember that for later. 184 00:25:14,930 --> 00:25:25,390 So for example, if you have a function like virtualalloc, all you have to do is you have to mark the operand, which is storing the size of buffer. 185 00:25:26,210 --> 00:25:28,050 Get buffer size. 186 00:25:29,190 --> 00:25:37,530 And the next thing is you mark the operand, which is storing the address of the buffer, which you are going to dump. 187 00:25:40,010 --> 00:25:41,990 Get buffer address. 188 00:25:42,910 --> 00:25:52,810 And last but not least, the final step is you mark the instruction or the location where you want to dump the buffer. 189 00:25:59,600 --> 00:26:03,220 So use marked address to dump buffer to file. 190 00:26:04,020 --> 00:26:05,500 That's it. 191 00:26:05,820 --> 00:26:14,980 Now you can go to the dump menu and execute the sample and the buffer gets automatically dumped at runtime. 192 00:26:14,980 --> 00:26:22,360 Once it is dumped, it is transferred over to IDA and you can store it somewhere on disk. 193 00:26:23,440 --> 00:26:33,460 And here you can see that it is the buffer which I've mentioned earlier, where the program has copied the PE string into. 194 00:26:36,020 --> 00:26:50,740 If you want to debug the sample inside of x64 debug, you can also generate x64 debug scripts, which are automatically setting a breakpoint at the location which you have. 195 00:26:50,740 --> 00:26:57,740 So once you generated the script, you can load it into x64 debug. 196 00:26:58,080 --> 00:27:08,990 All you have to do is to run the script, it will automatically stop the sample and break at the breakpoint which you have highlighted in IDA. 197 00:27:15,320 --> 00:27:25,160 So here we have reached the breakpoint, the script has finished, and now you can proceed debugging in x64 debug. 198 00:27:27,260 --> 00:27:32,900 The last feature which I would like to show you is how to create endless loops in binaries. 199 00:27:33,780 --> 00:27:46,660 So if you want to create an endless loop, you can just mark the line where you want to create the loop and then you select create executable with loop at marked address. 200 00:27:47,080 --> 00:27:48,720 Now DDR is creating a 201 00:27:52,660 --> 00:28:05,100 patched binary and you can move over to the DDR server side and you will find a patched binary inside of the samples directory. 202 00:28:09,210 --> 00:28:22,270 So now you can start this binary, just double click on it and at a certain point we are reaching this endless loop. 203 00:28:22,270 --> 00:28:29,630 So now we can attach our debugger to it and proceed debugging the sample. 204 00:28:36,280 --> 00:28:44,620 So after pausing the sample, of course first thing you have to do is you have to replace the patched bytes. 205 00:28:44,780 --> 00:28:54,000 The patched bytes of the endless loop will help in the DDR server output to see what kind of bytes you have to patch. 206 00:28:56,520 --> 00:29:11,430 Now you're just copying the address into this command and then finally you have the original commands back inside of the binary. 207 00:29:14,540 --> 00:29:25,200 So when we are proceeding to debug, you see that this changed to the original bytes and now you can just proceed debugging like usual. 208 00:29:25,940 --> 00:29:27,720 And that's it. 209 00:29:30,260 --> 00:29:36,420 Okay, so this was the installation and the feature walkthrough of DDR. 210 00:29:36,840 --> 00:29:44,340 Let's move on and have a look at some of the special cases and of course the best practices. 211 00:29:44,880 --> 00:29:49,080 The better you know DDR, the more efficient you can use DDR. 212 00:29:49,660 --> 00:29:56,440 And as usual, the easiest is to watch a quick live demo about it. 213 00:29:58,660 --> 00:30:05,700 When I start analyzing samples, I like to run a quick light trace. 214 00:30:05,700 --> 00:30:13,120 Light trace is only executing 20,000 instructions by default. 215 00:30:13,160 --> 00:30:15,300 You can change this default value. 216 00:30:15,300 --> 00:30:19,640 If you're running a light trace, you can probably set that up to 200,000. 217 00:30:19,640 --> 00:30:26,040 But this is in this case for this sample not necessary, so we can leave the default value. 218 00:30:29,830 --> 00:30:39,650 Once the light trace is executed, we can highlight the traced instructions to see which basic blocks were actually executed. 219 00:30:40,550 --> 00:30:46,070 This was pretty quick in this case, so let's see what's going on. 220 00:30:46,070 --> 00:30:54,530 Highlight traced instructions and we see that there are only four basic blocks which were actually executed. 221 00:30:54,530 --> 00:31:01,390 So it seems to be that there is some anti-analyzing checks going on. 222 00:31:01,390 --> 00:31:07,610 So let's go into the last function which might be responsible for this check. 223 00:31:13,400 --> 00:31:24,220 So when we are scrolling down a little bit, we see that it seems to be that this function is dynamically resolving the getNativeSystemInfo API call. 224 00:31:24,220 --> 00:31:26,360 It's using getProcessAddress. 225 00:31:26,360 --> 00:31:29,160 We see that pretty often in malware samples. 226 00:31:31,950 --> 00:31:38,470 Then it is storing the address in this variable. 227 00:31:39,870 --> 00:31:48,130 And a bit later on, it is subtracting 10 from this address. 228 00:31:48,630 --> 00:32:00,190 And a little bit below, we see that this value is pushed as an argument to the next function. 229 00:32:00,190 --> 00:32:11,410 So it seems to be that the first argument of this function is this getNativeSystemInfo API call function address minus 10. 230 00:32:12,350 --> 00:32:21,930 So when we are looking at the first argument here, we see that it is executing a couple of mathematical instructions. 231 00:32:22,330 --> 00:32:29,370 And it seems to be that it is just adding 10 to it. 232 00:32:29,370 --> 00:32:33,170 So it has restored the original address. 233 00:32:33,170 --> 00:32:43,170 And it seems to be that it is just calling the getNativeSystemInfo API call here at that point. 234 00:32:43,690 --> 00:32:49,330 Unfortunately, in real malware, this is often much more complicated. 235 00:32:50,030 --> 00:33:00,370 So in real malware, we often see that these calculations are distributed all over the place. 236 00:33:00,370 --> 00:33:03,190 And they are heavily obfuscated. 237 00:33:03,190 --> 00:33:11,090 So it's often very difficult to figure out what is actually called at this point. 238 00:33:11,170 --> 00:33:14,290 With DDR, that is much easier. 239 00:33:14,290 --> 00:33:21,150 You can just do a right click, and you can get the value of this function pointer. 240 00:33:22,070 --> 00:33:25,690 Just pick getValue for pointer and source operand. 241 00:33:29,140 --> 00:33:34,280 And then you see the value which was used at runtime. 242 00:33:34,800 --> 00:33:40,660 So it is confirming what we assumed getNativeSystemInfo is called. 243 00:33:42,240 --> 00:33:46,440 With this information, we can now go one level up. 244 00:33:46,440 --> 00:33:58,620 And we can change the name of this argument to function pointer getNativeSystemInfo minus 10. 245 00:33:59,060 --> 00:34:06,180 And we have also seen earlier in this function that there was one parameter pushed. 246 00:34:06,180 --> 00:34:09,700 And this is the second argument of this function. 247 00:34:09,700 --> 00:34:24,900 So if we are looking at the getNativeSystemInfo, we see that this is actually a pointer to the system infrastructure, which is storing all the system information. 248 00:34:25,620 --> 00:34:32,460 So again, we can go to the function above. 249 00:34:32,460 --> 00:34:37,100 And we can find the second argument here. 250 00:34:37,100 --> 00:34:43,580 And we can also rename it to something like systemInfo or whatever you like. 251 00:34:44,680 --> 00:35:01,600 As far as this is a stack variable, which is pointing to a structure, we can also do some housekeeping and quickly assign the right structure to it. 252 00:35:01,920 --> 00:35:10,680 So that makes it a little bit easier when we are proceeding the analysis to see what's going on. 253 00:35:10,680 --> 00:35:19,040 So here we can see that here is actually a comparison between the number of processors and three. 254 00:35:19,380 --> 00:35:29,640 With a closer look, we see that if the number of processors of the machine where the sample is running on is smaller than three, then 255 00:35:33,280 --> 00:35:38,320 we are just printing out a likely virtual machine detected. 256 00:35:38,320 --> 00:35:45,120 So if it has two or less processors, the sample assumes that it is running on a virtual machine. 257 00:35:45,200 --> 00:35:49,600 If it is more than two processors, it is returning zero. 258 00:35:50,260 --> 00:35:59,600 And again, if we go one level up, we can see here that it is comparing EAX. 259 00:35:59,660 --> 00:36:07,320 And only if it is zero, then it is proceeding with the rest of the malware code. 260 00:36:07,320 --> 00:36:09,740 If not, it is just exiting. 261 00:36:12,400 --> 00:36:21,460 Let's rename the function quickly to something like VMCheck and let's proceed analyzing. 262 00:36:21,940 --> 00:36:25,300 So of course, we are also interested in the rest of the code. 263 00:36:25,340 --> 00:36:35,460 And to make sure that we can execute it on a virtual machine, we can just toggle the EFlex like you have seen before. 264 00:36:35,460 --> 00:36:40,520 In this case, it's a jump zero, so the zero flags are fine. 265 00:36:40,740 --> 00:36:44,700 So let's run the trace again and wait for the results. 266 00:36:54,010 --> 00:36:59,490 Okay, so I've cheated now a little bit and fast forwarded the video. 267 00:36:59,490 --> 00:37:01,710 We run into a timeout. 268 00:37:01,710 --> 00:37:05,770 So we are seeing this warning message here. 269 00:37:05,770 --> 00:37:12,850 And it is telling us that the response from the DDR server took too long. 270 00:37:12,850 --> 00:37:21,830 By default, the plugin waits for 30 seconds to get the results from the DDR server, the trace for example. 271 00:37:22,150 --> 00:37:29,090 And if you like, you can change this behavior here under API timeout. 272 00:37:29,750 --> 00:37:37,230 You can increase the timeout, for example, to 60 seconds or to 100 seconds or whatever you think works. 273 00:37:37,230 --> 00:37:40,870 And then the plugin waits for a longer time. 274 00:37:41,170 --> 00:37:50,750 So you've seen earlier that you can also configure the number of instructions, for example, which are supposed to be analyzed. 275 00:37:50,930 --> 00:37:55,510 And you can play with these two values a little bit. 276 00:37:56,050 --> 00:38:02,950 Of course, if you're increasing the number of instructions, much more data will be collected. 277 00:38:02,950 --> 00:38:08,130 And the files which are going to be exchanged are also much bigger. 278 00:38:08,650 --> 00:38:16,730 So sometimes it helps to increase the timeout to do these kind of long traces. 279 00:38:16,910 --> 00:38:20,070 But nevertheless, make sure that you're not 280 00:38:23,210 --> 00:38:27,670 increasing the number of instructions to a too high value. 281 00:38:27,670 --> 00:38:36,170 Keep always in mind that it is also increasing the file size of the data which is collected. 282 00:38:37,970 --> 00:38:43,770 So coming back here to our issue that it timed out. 283 00:38:43,790 --> 00:38:54,450 We can, for example, now look over to the server side and we can check if there was some internal error. 284 00:38:54,450 --> 00:39:00,390 For example, there could be a bug inside of DDR which caused a crash, for example. 285 00:39:00,390 --> 00:39:03,170 Or there could be some other reason. 286 00:39:03,170 --> 00:39:06,150 A super endless loop or whatever. 287 00:39:06,450 --> 00:39:09,050 And a sleeper, whatever. 288 00:39:09,050 --> 00:39:13,790 And we see here that the analyzers run for 60 seconds. 289 00:39:13,790 --> 00:39:18,470 So it seems to be that it was successfully executed. 290 00:39:19,110 --> 00:39:29,750 When we are now going back to IDA, we can proceed with the analyzers of the malware to get an idea about what happened. 291 00:39:30,050 --> 00:39:36,210 And usually you would now check these instructions what's happening. 292 00:39:36,210 --> 00:39:39,770 Of course, I'm not doing that in detail here in the demo. 293 00:39:40,150 --> 00:39:48,630 And I know the result and the reason for the timeout in this case is a sleep timer. 294 00:39:48,630 --> 00:39:56,610 So you have a sleep timer here which is actually waiting for 60 seconds. 295 00:39:56,610 --> 00:39:59,750 And of course that is more than the 30 seconds. 296 00:39:59,890 --> 00:40:06,590 And we haven't reached the maximum number of instructions at that point yet. 297 00:40:06,590 --> 00:40:12,550 So the DDR server side is still trying to analyze the sample. 298 00:40:12,550 --> 00:40:19,890 But there are no new instructions before this sleep is not over. 299 00:40:20,290 --> 00:40:28,050 So this means that the analyzers are still going on the server side. 300 00:40:28,050 --> 00:40:33,310 But the plugin runs into the 30 seconds timeout. 301 00:40:33,450 --> 00:40:40,330 So we could now increase the timeout, for example, and just wait for a little bit longer. 302 00:40:40,330 --> 00:40:48,630 Or again, we can just here knob out these instructions and run it again. 303 00:40:49,150 --> 00:40:56,790 I don't like to wait, so I prefer using the knob out functionality. 304 00:40:56,830 --> 00:41:01,210 And now we are running the trace again. 305 00:41:02,690 --> 00:41:07,570 And now it should be a little bit quicker. 306 00:41:07,790 --> 00:41:09,910 So light trace done. 307 00:41:10,050 --> 00:41:17,930 And now we can clear the old highlighted instructions, clear highlighted instructions. 308 00:41:18,250 --> 00:41:22,250 And we can highlight it again. 309 00:41:22,250 --> 00:41:28,030 And now we can see the new path with all our patches which we have applied. 310 00:41:28,030 --> 00:41:37,390 Now you see that we have manipulated the VM check here, even if it has detected the VMware. 311 00:41:37,390 --> 00:41:43,910 Nevertheless, we toggle the E-flag here and we are going this way. 312 00:41:44,250 --> 00:41:54,350 And now it is checking here if its name is evilmalware.exe. 313 00:41:55,090 --> 00:42:02,190 And if that is not the case, then the sample is going this way. 314 00:42:02,370 --> 00:42:11,510 And a quick summary of what's happening here is it is copying itself over to the temp folder. 315 00:42:11,790 --> 00:42:31,450 And then finally here, after the sleep, it is creating the process and starting another instance of itself just from this other directory. 316 00:42:31,770 --> 00:42:40,590 So this is the reason why we are seeing that we are reaching here this exit call. 317 00:42:40,610 --> 00:42:50,010 And the sample seems to be... or the execution of the sample seems to be stopped at that point. 318 00:42:50,670 --> 00:42:54,470 In reality, it has started the new instance. 319 00:42:54,470 --> 00:42:58,730 And the new instance is running under this name. 320 00:42:58,730 --> 00:43:07,550 So it will now go this path and will proceed to execute the rest of the code. 321 00:43:08,410 --> 00:43:11,310 This should be enough for this sample. 322 00:43:11,310 --> 00:43:13,310 So let's move on to the next one. 323 00:43:13,310 --> 00:43:18,570 Actually, one which we found during a recent apt-temp campaign. 324 00:43:19,590 --> 00:43:26,050 It is an executable which looks like an XML file. 325 00:43:26,050 --> 00:43:33,230 But as you know, if you run that on the command line, it will execute it like any other normal executable. 326 00:43:33,230 --> 00:43:43,250 So to get an overview about what it is doing, as usual, we are just running a quick light trace with DDR. 327 00:43:43,890 --> 00:43:49,530 And when we are moving over to DDR, we suddenly see... oops, what that? 328 00:43:50,050 --> 00:43:52,010 The window disappeared. 329 00:43:52,010 --> 00:43:57,250 So it seems to be that maybe the process was killed or something like that. 330 00:43:57,250 --> 00:43:58,530 Interesting. 331 00:43:59,130 --> 00:44:01,910 So we are moving back to IDA. 332 00:44:01,910 --> 00:44:10,490 And we suddenly see that the light trace was nevertheless successfully executed. 333 00:44:10,770 --> 00:44:15,910 So it seems to be that the DDR process is still running in the background. 334 00:44:16,530 --> 00:44:18,650 So what's going on here? 335 00:44:18,650 --> 00:44:26,130 To get an idea, it's always a good idea to check the API calls which were executed. 336 00:44:26,230 --> 00:44:32,850 And when we are looking at those, we see that there's a couple of initialization going on. 337 00:44:33,810 --> 00:44:38,430 And stuff like rebuilding the IRT, for example. 338 00:44:38,430 --> 00:44:42,170 A lot of get process address calls. 339 00:44:42,530 --> 00:44:49,610 And after that, we suddenly see, oh, there's a show window API call. 340 00:44:49,610 --> 00:44:54,550 That looks interesting, because with show window, you can manipulate the window. 341 00:44:54,910 --> 00:45:08,170 And when we are looking into the disassembly, we see that it is using get console window to get the handle of its own window. 342 00:45:08,170 --> 00:45:11,250 And then it is executing show window. 343 00:45:11,390 --> 00:45:16,830 And show window is using ESI for the command show parameter. 344 00:45:17,110 --> 00:45:20,930 And ESI is cleared right before. 345 00:45:20,930 --> 00:45:26,150 So we can be pretty sure that ESI is zero in this case. 346 00:45:26,150 --> 00:45:37,730 But even if it would be a more complex function in a different sample, for example, of course, we can always use DDR to get an idea about what this value is. 347 00:45:37,730 --> 00:45:40,950 Here in our case, zeros, obviously. 348 00:45:41,590 --> 00:45:45,850 So it is handing over a zero to show window. 349 00:45:45,910 --> 00:46:00,970 And if we are having a closer look to the show window function, we see that the command show parameter is offering a couple of different options. 350 00:46:01,090 --> 00:46:07,850 And if it is zero, it is just hiding the window from the desktop. 351 00:46:07,870 --> 00:46:17,170 So we have solved the issue why the command window suddenly disappeared. 352 00:46:17,170 --> 00:46:18,390 It was not killed. 353 00:46:18,390 --> 00:46:21,350 It was just moved into the background. 354 00:46:21,870 --> 00:46:34,710 So this is one of the examples how you can pretty quickly analyze what's actually happening with your sample. 355 00:46:35,870 --> 00:46:41,610 And now you could either leave it like it is in this case, because it doesn't hurt. 356 00:46:41,610 --> 00:46:52,470 Or if you still want to see the window, you just go ahead and you kill these instructions, because you don't need them for anything else. 357 00:46:52,650 --> 00:46:58,570 You can just knock them out, about mark instructions. 358 00:46:58,970 --> 00:47:13,190 And then we are restoring the snapshot on the on the other side, on the DDR server side. 359 00:47:13,190 --> 00:47:19,870 And once it is restored, we can just run the sample again. 360 00:47:21,410 --> 00:47:23,890 Just do a glide trace again. 361 00:47:27,470 --> 00:47:40,020 And now we can see that it is running normally like before, but it is not hiding the window anymore, because we have knocked out these instructions. 362 00:47:40,730 --> 00:47:42,230 And we are done. 363 00:47:42,230 --> 00:47:46,020 And we can proceed with our analysis. 364 00:47:51,480 --> 00:47:53,520 Back to the presentation. 365 00:47:53,700 --> 00:48:00,980 Another special case which I would like to talk about is if you want to analyze the sample in an air-gapped environment. 366 00:48:01,240 --> 00:48:16,500 So for example, if the sample is doing excessive anti-VMware checks, or if you have to disable the networking for any reason, there are probably many cases why you want to analyze the sample on an air-gapped system. 367 00:48:16,500 --> 00:48:25,380 You can do that because the engine of DDR is implemented in a way that it is a command line tool. 368 00:48:25,380 --> 00:48:32,480 And it is heavily leveraging the DynamoRIO framework to do all the instrumentation. 369 00:48:32,660 --> 00:48:45,260 So at the end, the DDR server script is just executing this command line tool to inject the DDR DLL into the sample. 370 00:48:45,260 --> 00:48:56,260 The DDR DLL is the engine which is doing all the analysis, which is saving all the traces and the registers and so on. 371 00:48:56,620 --> 00:49:09,520 And if you're running this command tool via drun-cclient-dll and the sample-to-instrument, you will get a JSON file back. 372 00:49:09,520 --> 00:49:17,560 Or actually, you're getting two JSON files back, one for the instruction trace and one for the API trace. 373 00:49:18,520 --> 00:49:22,080 These JSON files are looking like this. 374 00:49:22,080 --> 00:49:28,700 So they have all the information per instruction in it. 375 00:49:28,700 --> 00:49:47,220 So all the registers, all the values of the registers at the point of the instruction, the E-flex, the disassembly, etc., plus the memory location, which might be interesting, and so on. 376 00:49:47,220 --> 00:49:59,940 And this is a JSON file which is getting transferred over to the IDA side, which is the IDA plugin reading to fill in its data structures. 377 00:49:59,940 --> 00:50:06,740 And with this file, you can then use the plugin like you have seen before. 378 00:50:07,760 --> 00:50:14,940 So you've seen earlier in the command that you have to hand over a configuration file. 379 00:50:14,940 --> 00:50:32,780 You will find in the docs directory of the GitHub repository a sample configuration file, which is heavily commented and gives you an idea about what kind of commands you can write into this configuration file. 380 00:50:32,880 --> 00:50:44,900 We will see in the demo, you can also use the output of the DDR server script to get an idea about what's going on and what kind of values you can use. 381 00:50:44,940 --> 00:50:54,440 So for example, you can just generate a certain command via the plugin and then you can check the generated configuration. 382 00:50:54,700 --> 00:50:57,500 But again, we will see that later on in the demo. 383 00:50:59,580 --> 00:51:08,520 So talking about the demo, let's have a look at it and see how that looks on the command line. 384 00:51:14,330 --> 00:51:23,370 So when you are running the command line tool the first time, you can cheat a little bit by looking at the server output. 385 00:51:23,370 --> 00:51:30,450 The DDR server is printing out the command which it is actually executing. 386 00:51:30,570 --> 00:51:41,310 And this is the command and the configuration which belongs to the command, which was automatically generated by the IDA plugin. 387 00:51:41,310 --> 00:51:51,490 So you can start with using the GUI and then you can have a look at the configuration file in the command line. 388 00:51:51,550 --> 00:51:57,850 And this gives you probably a good idea how these things are actually working. 389 00:51:58,130 --> 00:52:06,170 And for the details, again, you have the documentation in the docs directory of the GitHub repository. 390 00:52:07,350 --> 00:52:11,450 So let's just run this again. 391 00:52:17,330 --> 00:52:28,030 And once it is finished, we see that it has written all these trace files to the samples directory. 392 00:52:28,030 --> 00:52:31,410 So let's move over to the samples directory. 393 00:52:34,010 --> 00:52:39,990 And we see that we have all these generated traces here. 394 00:52:40,010 --> 00:52:46,230 But there are also further files like the DDR process trace. 395 00:52:46,230 --> 00:52:53,730 And the DDR process trace is a file which is logging all the processes which were started by the sample. 396 00:52:53,790 --> 00:52:58,790 And pretty much the same, but for threads, are these threads files. 397 00:52:58,790 --> 00:53:05,930 They include the information about which threads the certain processes have started. 398 00:53:06,150 --> 00:53:23,930 So if we are looking at the processes file, for example, we see that the original sample has executed a second process, the evilmalware.exe. 399 00:53:24,650 --> 00:53:33,230 And DDR is following all the threads and processes which the original sample is creating. 400 00:53:33,450 --> 00:53:43,750 So we have seen earlier in IDA the trace which was imported for the main thread and for the main process. 401 00:53:44,070 --> 00:53:52,750 We haven't seen the second process in IDA so far, but the trace was generated. 402 00:53:52,750 --> 00:54:10,970 So we can go back to IDA and we can import this one and then we have all the instructions which were executed by the process evilmalware.exe, the second instance of the buffertest.exe file. 403 00:54:11,070 --> 00:54:14,510 And let me show you how that works. 404 00:54:15,870 --> 00:54:25,730 Okay, so we are back in IDA and you hopefully remember the sample which we have looked at earlier. 405 00:54:25,730 --> 00:54:33,010 The buffertest.1, the one which was checking if its name was evilmalware.exe. 406 00:54:33,010 --> 00:54:41,250 And if that is not the case, it is copying itself to the temp folder and executing itself under this name again. 407 00:54:41,330 --> 00:54:54,880 And you remember that we were only following the main process here and we were able to highlight the instructions down to the point where the initial process exited. 408 00:54:55,740 --> 00:55:09,800 But of course we are also interested in the second part and what happens with the second instance and what kind of code is the second instance executing. 409 00:55:10,100 --> 00:55:23,520 One thing we could do, of course, is we could just manipulate the code again like we've done before, or now we are importing these files which we have just generated. 410 00:55:24,080 --> 00:55:44,560 So we can clear the highlighted instructions and we are using the loadddr trace button to go to the directory where we have imported these traces which we've seen earlier. 411 00:55:44,840 --> 00:55:49,880 So now I'm interested in the one of evilmalware.exe. 412 00:55:49,880 --> 00:56:01,000 So I'm loading this one for the trace commands and I'm loading this one for the API calls. 413 00:56:02,800 --> 00:56:04,940 So API calls. 414 00:56:04,940 --> 00:56:14,980 So now we have successfully imported these traces, one for the API calls and one for the instructions. 415 00:56:15,020 --> 00:56:42,160 And now we can use ddr like we've done it before and you see that the second instance which is running under evilmalware.exe is of course going this path and now we can proceed analyzing these parts and look what it is doing like we've done before. 416 00:56:43,160 --> 00:56:49,340 GetSourceValue or whatever helps us to understand what this sample is doing. 417 00:56:51,720 --> 00:57:05,420 The last thing which I would like to mention is that you should really keep in mind that it is good practice not to run traces for too many instructions. 418 00:57:05,420 --> 00:57:15,980 Keep in mind that stopping at every instruction and collecting all the registers and all the memory informations of course it takes a lot of time and consumes a lot of memory. 419 00:57:16,300 --> 00:57:22,640 So it's usually good practice to just mark the basic blocks you are interested in. 420 00:57:22,720 --> 00:57:51,460 So for example if we are just interested in the values of these two basic blocks it is usually a good idea to just select them at basic blocks to list and this one select at basic block to list and you can see that it was successful here and then run the trace just for the basic block list. 421 00:57:53,620 --> 00:57:56,180 And it is done. 422 00:57:56,180 --> 00:58:04,780 That is much faster, you don't have to wait for too long and you're not creating gigabytes of files. 423 00:58:05,040 --> 00:58:17,540 Just keep in mind that if you are doing that that you now only have these two basic blocks in the database. 424 00:58:17,560 --> 00:58:23,720 So all the others are not traced or not in the database in the moment. 425 00:58:23,720 --> 00:58:32,900 Which means that if you try to get a value from here of course you're running into an error. 426 00:58:33,020 --> 00:58:35,160 It's not in trace. 427 00:58:35,560 --> 00:58:44,420 It can be a little bit confusing in the beginning if you don't think about it but usually you are getting pretty quickly used to that. 428 00:58:44,640 --> 00:58:51,960 And now you can analyze the functions which you are actually interested in. 429 00:58:52,720 --> 00:58:55,960 GetSourceValue or whatever you are looking for. 430 00:58:56,460 --> 00:58:58,800 Okidoki, that's it. 431 00:59:00,220 --> 00:59:13,050 So you've seen that DDR is not replacing your brain but nevertheless it speeds up a lot of reversing tasks and it is usually a pretty big help in analyzing malware samples. 432 00:59:13,920 --> 00:59:21,420 With this I'm done for today and I'm giving back to the folks from the Blue Team Village.