[00:25.080 --> 00:30.340] Okay, hello everyone. My name is Paramount Kid and I welcome you to Reversing with Dynamic [00:30.340 --> 00:36.060] Data Resolver. If you are not already in the Discord chat, please go to blueteamvillage.org, [00:36.060 --> 00:41.600] click on the Discord channel link, and I would like you to give a warm welcome to Mr. Holger [00:42.200 --> 00:50.780] and let's start with the talk. Hi and welcome to my presentation, [00:50.780 --> 00:56.240] Reversing with Dynamic Data Resolver Best Practices. My name is Holger Unterwink. I'm [00:56.340 --> 01:00.920] a security researcher at Cisco Talos and I'm mainly focused on malware research, [01:00.920 --> 01:05.220] threat hunting, and tool development. If you want to follow me on Twitter, [01:05.220 --> 01:12.800] you can find me at hunterbr72. I'm the author of DDR and I will guide you through the different [01:12.800 --> 01:19.520] features of DDR today, the installation process, and I will show you some of the best practices, [01:19.520 --> 01:25.920] how to use the tool, and some of the special cases and caveats which you can [01:26.540 --> 01:30.560] see later on in the demos where you might can run into. [01:32.920 --> 01:39.260] So what is Dynamic Data Resolver? First of all, Dynamic Data Resolver is an instrumentation tool. [01:39.260 --> 01:46.420] It is instrumenting the binary so that you can trace all the instructions the binary is executing [01:46.980 --> 01:54.380] and it is collecting all kinds of data from strings to register values, memory locations, [01:54.380 --> 02:01.780] etc. etc. It comes with an IDA plugin which is controlling the backend so you can easily [02:02.420 --> 02:09.900] handle everything from this IDA plugin and you don't need to use the command line tools. You can [02:09.900 --> 02:18.880] and I will talk about that later on. DDR comes with an client-server architecture. [02:18.940 --> 02:27.400] So you have the DDR server which is running on the malware PC side, so the PC where you are [02:27.400 --> 02:34.960] executing malware, and you have the IDA plugin which is running inside of IDA on the analyst PC. [02:34.960 --> 02:40.940] It is highly recommended to separate these two machines. In theory, you can run all of that [02:40.940 --> 02:46.900] on one machine, but keep in mind that you are executing the malware at the end. [02:46.900 --> 02:53.140] So the malware really runs on that machine and you might not want to infect your machine [02:53.140 --> 03:00.120] where you have your IDA installation on. It'll be infected with malware. [03:02.940 --> 03:13.500] So what can I do with DDR? DDR was mainly built to resolve dynamic values and this is why I've [03:13.500 --> 03:19.320] called it a dynamic data resolver. But it comes with all kinds of other features. But for now, [03:19.320 --> 03:25.120] let's keep with the data resolving option you have in DDR. You have the option to resolve [03:25.120 --> 03:34.440] certain register values, for example. So if you want to know the absolute value of EDI or EBX or [03:34.440 --> 03:42.520] EAX, you can just do that with one click. You can also get the pointer to the memory this value is [03:42.520 --> 03:49.560] pointing to, or even the pointer pointer. And DDR also tries to detect if the address which is [03:49.560 --> 03:58.440] stored in a certain register, if that one points to a certain API call like virtual protect. [03:58.660 --> 04:06.940] And if that is the case, it will also resolve the API call so you can see the human readable name [04:06.940 --> 04:18.850] of the function call. After you have run a trace and DDR has all the instruction traced, [04:18.850 --> 04:26.510] you can highlight the instructions with a color. You can just highlight them depending on how many [04:26.510 --> 04:33.510] times they were executed. So you get a pretty quick overview about which basic blocks were [04:33.510 --> 04:39.150] executed by the program and how often these basic blocks were executed by the program. [04:39.190 --> 04:47.410] As you can see here on the slide, if you see a color which is a more warmer color, [04:47.410 --> 04:52.830] like red or purple, you know that this basic block or these instructions were [04:52.830 --> 04:59.730] executed many times. So it is likely that it is maybe a decoding routine or something like that. [04:59.730 --> 05:03.270] So that already gives you a good clue about what the sample is doing [05:03.270 --> 05:09.070] and what parts of the sample are executed and what other parts are maybe not executed. [05:10.330 --> 05:19.890] You can also get a table of all the API calls the sample has executed. So you can search [05:19.890 --> 05:26.550] through this list. You can search for certain API calls like a virtual alloc or something like that. [05:26.550 --> 05:31.830] And then you can do a double click on the line and you are jumping to the disassembly code [05:31.830 --> 05:39.990] where this API call was called. The same applies for strings. As I mentioned earlier, [05:39.990 --> 05:46.790] DDR tries to collect all the strings at runtime. And it is filling this table with these strings. [05:46.790 --> 05:52.910] And the table is again searchable. So you can look for certain interesting strings like PE, [05:52.910 --> 05:58.970] for example, if you're looking for a PE header, and then double click on this line [05:58.970 --> 06:06.890] and check out in the disassembly what's going on where this was used. [06:06.910 --> 06:10.530] And we will see all of that later on in the live demo. [06:13.580 --> 06:19.100] Another neat feature of DDR is that there's a smart way to dump buffers at runtime. [06:20.020 --> 06:30.120] So all you have to hand over to DDR is the size of the buffer, the address of the buffer, [06:30.120 --> 06:38.700] and when or where you want to dump the buffer. And we will also see that later on. For example, [06:38.700 --> 06:44.020] you just have to mark the operands in the disassembly which are storing these [06:44.020 --> 06:49.960] informations. The size, the address, and at the end where you want to dump the buffer. [06:53.600 --> 06:57.660] Unfortunately, often malware comes with anti-analyzing features. [06:57.660 --> 07:02.520] And it is not executed like it would be executed on a normal PC. [07:02.540 --> 07:09.320] If you're running it in a VMware, for example. So DDR comes with an option to patch the sample [07:09.320 --> 07:15.060] at runtime. So for example, you can knock out certain instructions. Or you can toggle the [07:15.060 --> 07:23.560] E-flag and manipulate the execution flow. So if there's a conditional branch, you can just [07:23.560 --> 07:28.420] toggle the E-flag and the conditional branch will do the exact opposite. [07:28.640 --> 07:32.220] But again, we will see that later on also in the demo. [07:32.540 --> 07:38.100] And last but not least, you also have the option to completely skip certain functions. [07:38.380 --> 07:43.700] You can just mark a function, skip it, and return a fake return value. [07:44.020 --> 07:48.500] So if you have, for example, a certain function in your malware sample which is [07:48.500 --> 07:56.500] checking for virtual machines or for anti-debugging stuff, you can just skip the function [07:56.500 --> 08:03.180] and return the value which is telling the sample that it is not getting debugged or that it's not [08:03.180 --> 08:08.920] running on a virtual machine. But again, we will see that later on in the demo. [08:11.220 --> 08:19.040] If IDA and DDR is not enough for you to analyze the sample, you can also create an x64 debug [08:19.040 --> 08:25.960] script which is automatically executing the sample. So it automatically loads the sample [08:26.590 --> 08:33.880] into x64 debug and it is automatically breaking at that address which you have [08:33.880 --> 08:40.240] highlighted in IDA when you have picked this menu point. [08:40.500 --> 08:48.520] If you don't like x64 debug, you also have the option to create a new executable of the [08:48.520 --> 08:55.740] binary with an endless loop at the marked address. So you can mark a certain location or certain [08:55.740 --> 09:05.160] address inside of IDA, pick this menu option, and then a new binary is generated which has an [09:05.160 --> 09:12.920] endless loop patched at that location. So you can start the binary, it starts to loop endlessly, [09:12.920 --> 09:20.080] and you can attach your favorite debugger to it, restore the bytes, and proceed debugging it. [09:22.620 --> 09:28.500] Okay, that should be enough for a quick overview about what you can do with DDR. [09:28.580 --> 09:36.380] In the upcoming demo, we will see all these features in detail again. So let's start with [09:36.380 --> 09:42.800] the installation. Of course, first of all, you have to download DDR. You can get it from [09:42.800 --> 09:49.720] its repository on GitHub. And once you have downloaded it, it comes with an installation [09:49.720 --> 09:56.140] script. And pretty much all you have to do is to execute this installation script, and it will [09:56.140 --> 10:04.360] guide you through the installation process. Again, we will see that later on in the next demo. [10:05.440 --> 10:11.900] If you want to stay up to date with the latest versions of DDR, you can follow me on Twitter. [10:11.900 --> 10:19.080] And every time I'm changing, fixing, or fixing anything, or releasing new stuff for DDR, [10:19.600 --> 10:29.820] I will announce that on my Twitter account. If this presentation is not enough for the [10:29.820 --> 10:36.200] information you are looking for, you can also find a very detailed blog post about DDR, [10:36.200 --> 10:41.640] which I've released end of May on our blog, which is also describing the different [10:42.820 --> 10:46.860] steps, the different features, and the best practices, [10:47.340 --> 10:53.000] and the caveats which you have to be aware of when you are working with DDR. [10:56.360 --> 11:06.320] DDR has a client-server architecture. Keep in mind that DDR is instrumenting the binary. So the [11:06.320 --> 11:15.660] binary is getting executed at the end. So it is highly recommended to split the analyzing part [11:15.660 --> 11:21.780] and the execution part, so that you have an analyst PC where your IDA is running on, including the [11:21.780 --> 11:28.620] plug-in, and a dedicated malware PC where you are executing the malware sample and analyzing [11:28.620 --> 11:37.780] the malware sample. The DDR server is controlling the backend of DDR, which is implemented [11:40.280 --> 11:46.860] using the DynamoRIO framework, and that one is at the end executing the sample, [11:46.860 --> 11:53.440] instrumenting the sample, and collecting all the data, which is then transferred back to the [11:53.440 --> 11:59.300] IDA plug-in. But we will also see that later on in a demo. [12:02.770 --> 12:10.870] Okay, so enough theory. Let's have a look how that looks in the real world. [12:12.570 --> 12:18.130] Installing DDR is pretty straightforward. All you have to do is to execute the [12:18.130 --> 12:24.190] ddr-installer.py script, and it is solving all the dependencies for you. [12:24.890 --> 12:31.370] After it has downloaded all the dependencies, it will ask you a couple of questions about the IDA [12:31.370 --> 12:38.370] installation directory, the IP address it is supposed to listen on, etc. etc. And after you [12:38.370 --> 12:45.470] have done that, you can start a local HTTP server, or in other words, the script is starting an HTTP [12:45.470 --> 12:54.430] server for you. And then you can move over to the IDA machine and access this HTTP server and [12:54.430 --> 13:04.090] download the DDR IDA plug-in site of the installation. Then you unzip the file and [13:04.090 --> 13:10.850] copy over the content to the traditional IDA plug-in directory. That will change in the next [13:10.850 --> 13:18.210] release, which is coming out very soon. And we will move over to the IDA user plug-in directory. [13:18.710 --> 13:23.630] So that has the advantage that you will not need any administrative rights anymore. [13:25.070 --> 13:30.450] Once you have done that, you need to figure out which Python version your IDA installation is [13:30.450 --> 13:38.430] using. And then you need to install two dependencies for this Python version, the [13:39.150 --> 13:46.610] requests library and the pfile library. And with this, you are ready to go. And you can move over [13:46.610 --> 13:55.770] to the server side again and start the DDR server. Okay, so after we've seen how the installation [13:55.770 --> 14:04.230] works, I can give you now a quick walkthrough of the different DDR features, which I've mentioned [14:04.230 --> 14:12.850] earlier. Okay, for this end, we have a dedicated analyst PC where IDA is running on, including the [14:12.850 --> 14:20.390] plug-in. And we have a dedicated machine where we are executing the malware on and where DDR [14:20.390 --> 14:30.990] server is running on. So let's move to this malware machine. Once on the malware machine side, [14:30.990 --> 14:38.390] we are starting the DDR server via the DDR server Python script. And when we are starting it, [14:38.390 --> 14:45.390] there's a little hind that you have to be aware of, that there is a caveat with [14:45.390 --> 14:54.710] Windows command prompt and Python scripts. If you're marking any text in the output window, you are [14:54.710 --> 15:02.330] freezing the Python application. So that means that if the plug-in would try to talk to the [15:02.330 --> 15:10.590] server now, you would run into a timeout. If that happens, you just need to [15:10.590 --> 15:17.450] hit escape a couple of times or just do a ctrl z and restart the server if you like. [15:23.310 --> 15:25.830] Okay, so let's move over to IDA. [15:30.850 --> 15:38.170] The first thing you usually want to do is you want to run a trace. A trace is filling all the internal [15:38.170 --> 15:45.630] data structures inside of DDR which are necessary for most of the other features. And you have two [15:45.630 --> 15:52.290] options, either to run a light trace or a full trace. A full trace is a trace which is collecting [15:52.290 --> 15:58.850] as much information as possible per instruction. So for example, it is saving all the [15:58.850 --> 16:06.530] register values for every single instruction. A light trace is only collecting a subset for [16:06.530 --> 16:14.010] these informations, but enough informations that you can have a look at the API calls, for example, [16:14.010 --> 16:21.430] or at the strings which were traced, or to get a source operand. And a light trace is usually [16:21.430 --> 16:29.530] something which I'm running when I start to analyze the sample. And if I just want to get an [16:29.530 --> 16:35.190] overview, if I just want to highlight the traced instructions, for example, or if I just want to [16:35.190 --> 16:42.450] see the API calls, then the light trace is good enough. Later on, when I'm analyzing a crypto [16:42.450 --> 16:49.090] algorithm, for example, and I need more informations, for example, all the registers, [16:49.090 --> 16:57.570] then I'm running a full trace. But I'm only running a full trace for a small address range or [16:57.570 --> 17:05.270] for a few basic blocks, for example. Because this is really time consuming and it is also consuming [17:05.470 --> 17:13.190] a lot of memory. So you usually want to limit the amount of instructions which you are instrumenting [17:13.190 --> 17:15.110] within full trace. [17:17.130 --> 17:24.270] Okay, enough about traces. Let's run the light trace and check how that looks like on the DDR [17:24.270 --> 17:31.930] server side. So the sample is executed and the dialog box which you have just seen just belongs [17:31.930 --> 17:38.390] to the sample code. It doesn't have anything to do with DDR. Don't be confused by that. [17:38.390 --> 17:46.010] Once the analysis is done, you can see that the trace log file is written to the same directory [17:46.010 --> 17:54.950] where the original sample is located. And you can also see that the temporary trace files [17:54.950 --> 18:02.670] were deleted based on a server command and then transferred over to the IDA plugin. So now we can [18:02.670 --> 18:10.610] switch back to IDA. And we also see this method can switch back to IDA. And we also see this [18:10.610 --> 18:21.510] message inside of IDA that the light trace was done successfully. So this means that DDR now has [18:21.510 --> 18:28.090] all the information it needs. And we can execute other features like highlighted traced instruction, [18:28.650 --> 18:34.910] which is giving us an overview about which basic blocks were executed or which instructions [18:34.910 --> 18:48.580] were executed. Okay, so let's move to the next feature. You can nop out instructions at runtime. [18:49.580 --> 18:56.560] So if you have certain instructions which you want to get rid of, like the dialog box which [18:56.560 --> 19:03.560] we have seen earlier, you can just mark these instructions and you go to the patch menu in DDR. [19:04.060 --> 19:11.030] And then the next time you execute the sample, so for example you run a new trace, [19:11.340 --> 19:17.480] then these instructions are nopped out, they're not getting executed anymore. And you can see here [19:18.000 --> 19:25.060] that it is responding much faster because we didn't have the pop-up of the dialog box [19:25.060 --> 19:34.830] and the sample immediately proceeded with execution. Okay, the next feature which I would [19:34.830 --> 19:41.330] like to show you is how you can use the dynamic values which were collected by the trace. [19:41.650 --> 19:47.190] Now first we are doing a trace again. This time we are just doing a trace over a couple of [19:47.190 --> 19:54.590] instructions. Now you're picking full trace for marked address range. And once this is done, [19:54.590 --> 20:01.910] we have all the values from these instructions inside of the database. So we can just go to [20:01.910 --> 20:08.310] get value for source operand and we are getting the value for RAX in this case. [20:11.140 --> 20:17.560] Or we can just get the values from memory pointers like you can see here, [20:17.560 --> 20:22.700] or all kinds of other information DDR has collected. [20:49.100 --> 20:55.660] The next nice feature is that you can collect all the strings and API calls at runtime. [20:56.320 --> 21:04.620] You can show both of them via tables where the DDR menu. So if we are looking at the strings, [21:04.620 --> 21:10.680] for example, this is a list of all the strings which we have collected at runtime. And of course [21:10.680 --> 21:15.960] you can also search for something in there, like PE for example. And if you're double clicking [21:15.960 --> 21:23.000] on the line, then you're jumping to the line in the assembly where it is used. [21:24.640 --> 21:29.620] You can also have a look at the API calls which were executed at runtime. [21:29.880 --> 21:36.280] And again, the same applies like for strings. You can search for something and double click on it. [21:36.280 --> 21:41.820] And then you see where it is used inside of the code. [21:43.880 --> 21:49.660] You have seen earlier that you can manipulate the code flow by nopping out instructions. [21:49.960 --> 21:55.240] But there are also other options inside of DDR which are manipulating the code flow. [21:55.240 --> 22:01.780] The next one which I would like to talk about is the option to toggle the E-flags. So for example, [22:01.780 --> 22:07.560] if we have a code like this, where we have a conditional jump and a comparison before, [22:07.560 --> 22:14.440] then we can toggle the E-flag at the jump. In this case, you have to know that EAX can [22:14.440 --> 22:21.680] never be bigger than 5. So at least in theory, this jump should always be taken in this code. [22:21.680 --> 22:27.500] And the program should print out main A is not greater than 5. [22:28.560 --> 22:35.000] If we want to manipulate that, we can just mark the GLAE instruction, do a right click, [22:35.000 --> 22:38.360] and go to the patch menu inside of DDR. [22:43.270 --> 22:49.750] Inside of the patch menu, we pick a toggle E-flag. In this case, we have to toggle the SF-flag. [22:50.370 --> 22:56.330] And once this is done, we can now just run the sample if we want. [22:56.570 --> 23:06.190] So for example, again over the patch menu, if we pick that one, then the sample is just [23:06.190 --> 23:14.870] getting executed. But we could also use any other feature of DDR, running a trace or doing a dump, [23:14.870 --> 23:22.830] which we will see later on. All these patches which I have applied will work for all the DDR [23:22.830 --> 23:33.830] features. Once we executed it, then we can move over to the DDR side and check the output of the [23:33.830 --> 23:44.370] file. Sorry, of the executable. So here you can see that the patch worked, and the program printed [23:44.370 --> 23:54.160] out A is greater than 5, and this should never happen. The last option you have is you can skip functions [23:54.160 --> 24:02.560] at runtime. So for example, if we have my function 1 here in this case, maybe something which is doing [24:02.560 --> 24:09.400] some anti-analyzing, anti-debugging stuff, you can just skip it and you can fake the return value. [24:09.400 --> 24:15.860] You're just marking the first instruction in the function, and you are going again to the patch [24:15.860 --> 24:24.640] menu, skip function at marked address at runtime, and you hand over the faked return value, and that's it. [24:28.930 --> 24:32.350] Now you can execute the sample again. [24:33.970 --> 24:42.470] And if we are moving over to the DDR server side, we see that the sample is getting executed, [24:43.310 --> 24:51.310] and in the output of the sample, we see that the my function 1 output is gone, [24:51.310 --> 24:55.270] because the my function 1 is not executed anymore. [24:55.830 --> 25:03.450] And another main function of DDR is that you can dump buffers at runtime. [25:03.530 --> 25:10.610] And you can do that in a smart way. Later on, this string will be copied into this buffer, [25:10.610 --> 25:17.210] which we are going to dump. So remember that for later. So for example, if you have a function [25:17.210 --> 25:24.310] like virtualalloc, all you have to do is you have to mark the operand, which is storing the size of [25:24.310 --> 25:35.090] buffer. Get buffer size. And the next thing is you mark the operand, which is storing the address [25:35.090 --> 25:44.770] of the buffer, which you are going to dump. Get buffer address. And last but not least, [25:45.490 --> 25:52.810] the final step is you mark the instruction or the location where you want to dump the buffer. [25:59.600 --> 26:08.440] So use marked address to dump buffer to file. That's it. Now you can go to the dump menu and [26:08.440 --> 26:16.420] execute the sample and the buffer gets automatically dumped at runtime. Once it is dumped, [26:16.420 --> 26:22.360] it is transferred over to IDA and you can store it somewhere on disk. [26:23.440 --> 26:28.300] And here you can see that it is the buffer which I've mentioned earlier, [26:28.300 --> 26:33.460] where the program has copied the PE string into. [26:36.020 --> 26:45.520] If you want to debug the sample inside of x64 debug, you can also generate x64 debug scripts, [26:45.520 --> 26:51.720] which are automatically setting a breakpoint at the location which you have. So once you [26:51.720 --> 27:00.920] generated the script, you can load it into x64 debug. All you have to do is to run the script, [27:00.920 --> 27:08.990] it will automatically stop the sample and break at the breakpoint which you have highlighted in IDA. [27:15.320 --> 27:20.420] So here we have reached the breakpoint, the script has finished, [27:20.420 --> 27:25.160] and now you can proceed debugging in x64 debug. [27:27.260 --> 27:32.900] The last feature which I would like to show you is how to create endless loops in binaries. [27:33.780 --> 27:39.960] So if you want to create an endless loop, you can just mark the line where you want to create the [27:39.960 --> 27:48.720] loop and then you select create executable with loop at marked address. Now DDR is creating a [27:52.660 --> 28:01.560] patched binary and you can move over to the DDR server side and you will find a patched binary [28:01.560 --> 28:16.630] inside of the samples directory. So now you can start this binary, just double click on it and [28:17.990 --> 28:22.270] at a certain point we are reaching this endless loop. [28:22.270 --> 28:29.630] So now we can attach our debugger to it and proceed debugging the sample. [28:36.280 --> 28:42.940] So after pausing the sample, of course first thing you have to do is you have to replace [28:42.940 --> 28:48.520] the patched bytes. The patched bytes of the endless loop will help in the DDR server [28:49.080 --> 28:54.000] output to see what kind of bytes you have to patch. [28:56.520 --> 29:02.040] Now you're just copying the address into this command [29:03.520 --> 29:11.430] and then finally you have the original commands back inside of the binary. [29:14.540 --> 29:20.220] So when we are proceeding to debug, you see that this changed to the original [29:20.220 --> 29:25.200] bytes and now you can just proceed debugging like usual. [29:25.940 --> 29:27.720] And that's it. [29:30.260 --> 29:36.420] Okay, so this was the installation and the feature walkthrough of DDR. [29:36.840 --> 29:44.340] Let's move on and have a look at some of the special cases and of course the best practices. [29:44.880 --> 29:49.080] The better you know DDR, the more efficient you can use DDR. [29:49.660 --> 29:56.440] And as usual, the easiest is to watch a quick live demo about it. [29:58.660 --> 30:05.700] When I start analyzing samples, I like to run a quick light trace. [30:05.700 --> 30:13.120] Light trace is only executing 20,000 instructions by default. [30:13.160 --> 30:16.840] You can change this default value. If you're running a light trace, [30:16.840 --> 30:19.640] you can probably set that up to 200,000. [30:19.640 --> 30:26.040] But this is in this case for this sample not necessary, so we can leave the default value. [30:29.830 --> 30:36.690] Once the light trace is executed, we can highlight the traced instructions to see which [30:37.470 --> 30:39.650] basic blocks were actually executed. [30:40.550 --> 30:46.070] This was pretty quick in this case, so let's see what's going on. [30:46.070 --> 30:51.650] Highlight traced instructions and we see that there are only four [30:51.650 --> 30:54.530] basic blocks which were actually executed. [30:54.530 --> 31:01.390] So it seems to be that there is some anti-analyzing checks going on. [31:01.390 --> 31:07.610] So let's go into the last function which might be responsible for this check. [31:13.400 --> 31:19.220] So when we are scrolling down a little bit, we see that it seems to be that this function is [31:19.220 --> 31:24.220] dynamically resolving the getNativeSystemInfo API call. [31:24.220 --> 31:29.160] It's using getProcessAddress. We see that pretty often in malware samples. [31:31.950 --> 31:38.470] Then it is storing the address in this variable. [31:39.870 --> 31:48.130] And a bit later on, it is subtracting 10 from this address. [31:48.630 --> 32:00.190] And a little bit below, we see that this value is pushed as an argument to the next function. [32:00.190 --> 32:04.570] So it seems to be that the first argument of this function [32:05.070 --> 32:11.410] is this getNativeSystemInfo API call function address minus 10. [32:12.350 --> 32:19.850] So when we are looking at the first argument here, we see that it is executing a couple [32:19.850 --> 32:24.970] of mathematical instructions. And it seems to be that it is just [32:26.650 --> 32:33.170] adding 10 to it. So it has restored the original address. [32:33.170 --> 32:43.170] And it seems to be that it is just calling the getNativeSystemInfo API call here at that point. [32:43.690 --> 32:49.330] Unfortunately, in real malware, this is often much more complicated. [32:50.030 --> 32:58.090] So in real malware, we often see that these calculations are distributed [32:58.870 --> 33:03.190] all over the place. And they are heavily obfuscated. [33:03.190 --> 33:11.090] So it's often very difficult to figure out what is actually called at this point. [33:11.170 --> 33:16.150] With DDR, that is much easier. You can just do a right click, [33:16.150 --> 33:21.150] and you can get the value of this function pointer. [33:22.070 --> 33:25.690] Just pick getValue for pointer and source operand. [33:29.140 --> 33:34.280] And then you see the value which was used at runtime. [33:34.800 --> 33:40.660] So it is confirming what we assumed getNativeSystemInfo is called. [33:42.240 --> 33:46.440] With this information, we can now go one level up. [33:46.440 --> 33:58.620] And we can change the name of this argument to function pointer getNativeSystemInfo minus 10. [33:59.060 --> 34:06.180] And we have also seen earlier in this function that there was one parameter pushed. [34:06.180 --> 34:09.700] And this is the second argument of this function. [34:09.700 --> 34:14.680] So if we are looking at the getNativeSystemInfo, [34:14.680 --> 34:21.540] we see that this is actually a pointer to the system infrastructure, [34:21.540 --> 34:24.900] which is storing all the system information. [34:25.620 --> 34:32.460] So again, we can go to the function above. [34:32.460 --> 34:37.100] And we can find the second argument here. [34:37.100 --> 34:43.580] And we can also rename it to something like systemInfo or whatever you like. [34:44.680 --> 34:50.600] As far as this is a stack variable, which is pointing to a structure, [34:51.060 --> 35:01.600] we can also do some housekeeping and quickly assign the right structure to it. [35:01.920 --> 35:10.680] So that makes it a little bit easier when we are proceeding the analysis to see what's going on. [35:10.680 --> 35:16.540] So here we can see that here is actually a comparison between the number of processors [35:17.400 --> 35:23.980] and three. With a closer look, we see that if the number of processors [35:24.800 --> 35:29.640] of the machine where the sample is running on is smaller than three, then [35:33.280 --> 35:38.320] we are just printing out a likely virtual machine detected. [35:38.320 --> 35:45.120] So if it has two or less processors, the sample assumes that it is running on a virtual machine. [35:45.200 --> 35:49.600] If it is more than two processors, it is returning zero. [35:50.260 --> 35:59.600] And again, if we go one level up, we can see here that it is comparing EAX. [35:59.660 --> 36:07.320] And only if it is zero, then it is proceeding with the rest of the malware code. [36:07.320 --> 36:09.740] If not, it is just exiting. [36:12.400 --> 36:21.460] Let's rename the function quickly to something like VMCheck and let's proceed analyzing. [36:21.940 --> 36:27.200] So of course, we are also interested in the rest of the code. And to make sure that we can [36:27.840 --> 36:35.460] execute it on a virtual machine, we can just toggle the EFlex like you have seen before. [36:35.460 --> 36:40.520] In this case, it's a jump zero, so the zero flags are fine. [36:40.740 --> 36:44.700] So let's run the trace again and wait for the results. [36:54.010 --> 37:01.710] Okay, so I've cheated now a little bit and fast forwarded the video. We run into a timeout. [37:01.710 --> 37:10.490] So we are seeing this warning message here. And it is telling us that the response from [37:10.490 --> 37:18.470] the DDR server took too long. By default, the plugin waits for 30 seconds to get the results [37:18.470 --> 37:26.170] from the DDR server, the trace for example. And if you like, you can change this behavior here [37:27.030 --> 37:34.930] under API timeout. You can increase the timeout, for example, to 60 seconds or to 100 seconds or [37:34.930 --> 37:42.790] whatever you think works. And then the plugin waits for a longer time. So you've seen earlier [37:42.790 --> 37:49.330] that you can also configure the number of instructions, for example, which are supposed [37:49.330 --> 37:57.510] to be analyzed. And you can play with these two values a little bit. Of course, if you're [37:57.510 --> 38:04.350] increasing the number of instructions, much more data will be collected. And the files which are [38:04.350 --> 38:13.250] going to be exchanged are also much bigger. So sometimes it helps to increase the timeout to [38:13.250 --> 38:20.070] do these kind of long traces. But nevertheless, make sure that you're not [38:23.210 --> 38:29.990] increasing the number of instructions to a too high value. Keep always in mind that it is also [38:29.990 --> 38:41.630] increasing the file size of the data which is collected. So coming back here to our issue [38:41.630 --> 38:52.890] that it timed out. We can, for example, now look over to the server side and we can check if there [38:52.890 --> 38:59.230] was some internal error. For example, there could be a bug inside of DDR which caused a crash, for [38:59.230 --> 39:08.230] example. Or there could be some other reason. A super endless loop or whatever. And a sleeper, [39:08.230 --> 39:15.810] whatever. And we see here that the analyzers run for 60 seconds. So it seems to be that it was [39:15.810 --> 39:26.090] successfully executed. When we are now going back to IDA, we can proceed with the analyzers [39:26.090 --> 39:33.130] of the malware to get an idea about what happened. And usually you would now check these [39:33.130 --> 39:39.770] instructions what's happening. Of course, I'm not doing that in detail here in the demo. [39:40.150 --> 39:48.630] And I know the result and the reason for the timeout in this case is a sleep timer. [39:48.630 --> 39:57.830] So you have a sleep timer here which is actually waiting for 60 seconds. And of course that is more [39:57.830 --> 40:05.310] than the 30 seconds. And we haven't reached the maximum number of instructions at that point [40:05.310 --> 40:13.450] yet. So the DDR server side is still trying to analyze the sample. But there are no new [40:13.450 --> 40:24.370] instructions before this sleep is not over. So this means that the analyzers are still [40:24.370 --> 40:33.310] going on the server side. But the plugin runs into the 30 seconds timeout. [40:33.450 --> 40:41.710] So we could now increase the timeout, for example, and just wait for a little bit longer. Or again, [40:41.710 --> 40:52.150] we can just here knob out these instructions and run it again. I don't like to wait, so I prefer [40:53.050 --> 41:01.210] using the knob out functionality. And now we are running the trace again. [41:02.690 --> 41:12.550] And now it should be a little bit quicker. So light trace done. And now we can clear [41:13.210 --> 41:22.390] the old highlighted instructions, clear highlighted instructions. And we can highlight it again. And [41:22.390 --> 41:30.150] now we can see the new path with all our patches which we have applied. Now you see that we have [41:30.150 --> 41:39.130] manipulated the VM check here, even if it has detected the VMware. Nevertheless, we toggle the [41:39.130 --> 41:54.350] E-flag here and we are going this way. And now it is checking here if its name is evilmalware.exe. [41:55.090 --> 42:05.690] And if that is not the case, then the sample is going this way. And a quick summary of what's [42:05.690 --> 42:17.090] happening here is it is copying itself over to the temp folder. And then finally here, after the sleep, [42:18.030 --> 42:31.450] it is creating the process and starting another instance of itself just from this other directory. [42:31.770 --> 42:41.850] So this is the reason why we are seeing that we are reaching here this exit call. And the sample [42:41.850 --> 42:50.010] seems to be... or the execution of the sample seems to be stopped at that point. [42:50.670 --> 42:58.730] In reality, it has started the new instance. And the new instance is running under this name. [42:58.730 --> 43:07.550] So it will now go this path and will proceed to execute the rest of the code. [43:08.410 --> 43:13.310] This should be enough for this sample. So let's move on to the next one. [43:13.310 --> 43:18.570] Actually, one which we found during a recent apt-temp campaign. [43:19.590 --> 43:28.970] It is an executable which looks like an XML file. But as you know, if you run that on the command [43:28.970 --> 43:36.350] line, it will execute it like any other normal executable. So to get an overview about what it [43:36.350 --> 43:45.830] is doing, as usual, we are just running a quick light trace with DDR. And when we are moving over [43:45.830 --> 43:53.410] to DDR, we suddenly see... oops, what that? The window disappeared. So it seems to be that [43:54.030 --> 44:01.910] maybe the process was killed or something like that. Interesting. So we are moving back to IDA. [44:01.910 --> 44:10.490] And we suddenly see that the light trace was nevertheless successfully executed. [44:10.770 --> 44:15.910] So it seems to be that the DDR process is still running in the background. [44:16.530 --> 44:24.730] So what's going on here? To get an idea, it's always a good idea to check the API calls which [44:24.730 --> 44:31.370] were executed. And when we are looking at those, we see that there's a couple of initialization [44:31.370 --> 44:42.170] going on. And stuff like rebuilding the IRT, for example. A lot of get process address calls. [44:42.530 --> 44:50.810] And after that, we suddenly see, oh, there's a show window API call. That looks interesting, [44:50.810 --> 44:57.830] because with show window, you can manipulate the window. And when we are looking into the [44:57.830 --> 45:08.270] disassembly, we see that it is using get console window to get the handle of its own window. And [45:08.270 --> 45:16.830] then it is executing show window. And show window is using ESI for the command show parameter. [45:17.110 --> 45:26.150] And ESI is cleared right before. So we can be pretty sure that ESI is zero in this case. [45:26.150 --> 45:30.990] But even if it would be a more complex function in a different sample, for example, [45:30.990 --> 45:39.270] of course, we can always use DDR to get an idea about what this value is. Here in our case, [45:39.270 --> 45:48.890] zeros, obviously. So it is handing over a zero to show window. And if we are having a closer look [45:48.890 --> 45:58.530] to the show window function, we see that the command show parameter is offering a couple of [45:58.530 --> 46:08.950] different options. And if it is zero, it is just hiding the window from the desktop. So we have [46:08.950 --> 46:19.430] solved the issue why the command window suddenly disappeared. It was not killed. It was just moved [46:19.430 --> 46:27.450] into the background. So this is one of the examples how you can pretty quickly analyze [46:30.110 --> 46:34.710] what's actually happening with your sample. [46:35.870 --> 46:42.730] And now you could either leave it like it is in this case, because it doesn't hurt. Or if you [46:42.730 --> 46:49.890] still want to see the window, you just go ahead and you kill these instructions, because you [46:49.890 --> 46:56.570] don't need them for anything else. You can just knock them out, [46:56.570 --> 47:08.330] about mark instructions. And then we are restoring the snapshot on the [47:09.710 --> 47:19.870] on the other side, on the DDR server side. And once it is restored, we can just run the sample again. [47:21.410 --> 47:23.890] Just do a glide trace again. [47:27.470 --> 47:34.390] And now we can see that it is running normally like before, but it is not [47:34.930 --> 47:40.020] hiding the window anymore, because we have knocked out these instructions. [47:40.730 --> 47:46.020] And we are done. And we can proceed with our analysis. [47:51.480 --> 47:57.080] Back to the presentation. Another special case which I would like to talk about is if you [47:57.080 --> 48:03.140] want to analyze the sample in an air-gapped environment. So for example, if the sample is [48:03.140 --> 48:10.640] doing excessive anti-VMware checks, or if you have to disable the networking for any reason, [48:10.640 --> 48:16.500] there are probably many cases why you want to analyze the sample on an air-gapped system. [48:16.500 --> 48:24.460] You can do that because the engine of DDR is implemented in a way that it is a command line [48:24.460 --> 48:32.480] tool. And it is heavily leveraging the DynamoRIO framework to do all the instrumentation. [48:32.660 --> 48:39.380] So at the end, the DDR server script is just executing this command line tool to [48:40.340 --> 48:50.600] inject the DDR DLL into the sample. The DDR DLL is the engine which is doing all the analysis, [48:50.600 --> 48:58.580] which is saving all the traces and the registers and so on. And if you're running this command [48:58.580 --> 49:09.520] tool via drun-cclient-dll and the sample-to-instrument, you will get a JSON file back. [49:09.520 --> 49:15.500] Or actually, you're getting two JSON files back, one for the instruction trace and one [49:15.500 --> 49:24.040] for the API trace. These JSON files are looking like this. So they have all the [49:24.040 --> 49:32.480] information per instruction in it. So all the registers, all the values of the registers [49:33.440 --> 49:43.760] at the point of the instruction, the E-flex, the disassembly, etc., plus the memory location, [49:43.760 --> 49:50.880] which might be interesting, and so on. And this is a JSON file which is getting transferred over [49:50.880 --> 49:59.940] to the IDA side, which is the IDA plugin reading to fill in its data structures. [49:59.940 --> 50:06.740] And with this file, you can then use the plugin like you have seen before. [50:07.760 --> 50:14.940] So you've seen earlier in the command that you have to hand over a configuration file. [50:14.940 --> 50:23.080] You will find in the docs directory of the GitHub repository a sample configuration file, [50:23.080 --> 50:29.460] which is heavily commented and gives you an idea about what kind of commands you can [50:30.140 --> 50:37.560] write into this configuration file. We will see in the demo, you can also use the output of the [50:37.560 --> 50:44.900] DDR server script to get an idea about what's going on and what kind of values you can use. [50:44.940 --> 50:51.920] So for example, you can just generate a certain command via the plugin and then you can check the [50:51.920 --> 50:57.500] generated configuration. But again, we will see that later on in the demo. [50:59.580 --> 51:08.520] So talking about the demo, let's have a look at it and see how that looks on the command line. [51:14.330 --> 51:20.890] So when you are running the command line tool the first time, you can cheat a little bit by [51:20.890 --> 51:29.050] looking at the server output. The DDR server is printing out the command which it is actually [51:29.050 --> 51:35.930] executing. And this is the command and the configuration which belongs to the command, [51:35.930 --> 51:44.470] which was automatically generated by the IDA plugin. So you can start with using the GUI [51:44.470 --> 51:53.010] and then you can have a look at the configuration file in the command line. And this gives you [51:53.010 --> 51:59.870] probably a good idea how these things are actually working. And for the details, [51:59.870 --> 52:06.170] again, you have the documentation in the docs directory of the GitHub repository. [52:07.350 --> 52:11.450] So let's just run this again. [52:17.330 --> 52:26.930] And once it is finished, we see that it has written all these trace files to the samples [52:26.930 --> 52:31.410] directory. So let's move over to the samples directory. [52:34.010 --> 52:42.510] And we see that we have all these generated traces here. But there are also further files [52:43.070 --> 52:51.010] like the DDR process trace. And the DDR process trace is a file which is logging all the processes [52:51.010 --> 52:57.910] which were started by the sample. And pretty much the same, but for threads, are these threads [52:57.910 --> 53:05.930] files. They include the information about which threads the certain processes have started. [53:06.150 --> 53:11.950] So if we are looking at the processes file, for example, [53:12.670 --> 53:23.930] we see that the original sample has executed a second process, the evilmalware.exe. [53:24.650 --> 53:33.230] And DDR is following all the threads and processes which the original sample is creating. [53:33.450 --> 53:40.670] So we have seen earlier in IDA the trace which was imported for the main [53:41.300 --> 53:50.330] thread and for the main process. We haven't seen the second process in IDA so far, but [53:50.330 --> 54:00.090] the trace was generated. So we can go back to IDA and we can import this one and then we have [54:00.090 --> 54:07.490] all the instructions which were executed by the process evilmalware.exe, the second instance [54:07.490 --> 54:14.510] of the buffertest.exe file. And let me show you how that works. [54:15.870 --> 54:24.770] Okay, so we are back in IDA and you hopefully remember the sample which we have looked at [54:24.770 --> 54:33.010] earlier. The buffertest.1, the one which was checking if its name was evilmalware.exe. [54:33.010 --> 54:39.070] And if that is not the case, it is copying itself to the temp folder and executing itself [54:39.070 --> 54:46.790] under this name again. And you remember that we were only following the main process here and [54:46.790 --> 54:54.880] we were able to highlight the instructions down to the point where the initial process exited. [54:55.740 --> 55:05.240] But of course we are also interested in the second part and what happens with the second [55:05.240 --> 55:11.420] instance and what kind of code is the second instance executing. One thing we could do, [55:11.420 --> 55:17.060] of course, is we could just manipulate the code again like we've done before, [55:17.060 --> 55:23.520] or now we are importing these files which we have just generated. [55:24.080 --> 55:33.320] So we can clear the highlighted instructions and we are using the loadddr trace [55:34.400 --> 55:44.560] button to go to the directory where we have imported these traces which we've seen earlier. [55:44.840 --> 55:52.900] So now I'm interested in the one of evilmalware.exe. So I'm loading this one for the trace [55:52.900 --> 56:01.000] commands and I'm loading this one for the API calls. [56:02.800 --> 56:11.980] So API calls. So now we have successfully imported these traces, one for the API calls and [56:11.980 --> 56:20.500] one for the instructions. And now we can use ddr like we've done it before and you see that [56:22.120 --> 56:29.100] the second instance which is running under evilmalware.exe is of course going this path [56:29.620 --> 56:42.160] and now we can proceed analyzing these parts and look what it is doing like we've done before. [56:43.160 --> 56:49.340] GetSourceValue or whatever helps us to understand what this sample is doing. [56:51.720 --> 56:57.620] The last thing which I would like to mention is that you should really keep in mind that [56:58.420 --> 57:06.460] it is good practice not to run traces for too many instructions. Keep in mind that [57:06.460 --> 57:10.980] stopping at every instruction and collecting all the registers and all the memory informations [57:11.340 --> 57:18.280] of course it takes a lot of time and consumes a lot of memory. So it's usually good practice [57:18.800 --> 57:25.160] to just mark the basic blocks you are interested in. So for example if we are just interested in [57:25.160 --> 57:31.740] the values of these two basic blocks it is usually a good idea to just select them [57:31.740 --> 57:42.380] at basic blocks to list and this one select at basic block to list and you can see that [57:42.380 --> 57:51.460] it was successful here and then run the trace just for the basic block list. [57:53.620 --> 58:01.920] And it is done. That is much faster, you don't have to wait for too long and you're not creating [58:01.920 --> 58:09.560] gigabytes of files. Just keep in mind that if you are doing that [58:11.320 --> 58:20.880] that you now only have these two basic blocks in the database. So all the others are not traced [58:21.500 --> 58:28.440] or not in the database in the moment. Which means that if you try to get a value from here [58:29.080 --> 58:37.440] of course you're running into an error. It's not in trace. It can be a little bit confusing [58:37.440 --> 58:43.500] in the beginning if you don't think about it but usually you are getting pretty quickly used to [58:43.500 --> 58:51.960] that. And now you can analyze the functions which you are actually interested in. [58:52.720 --> 58:58.800] GetSourceValue or whatever you are looking for. Okidoki, that's it. [59:00.220 --> 59:07.200] So you've seen that DDR is not replacing your brain but nevertheless it speeds up a lot of [59:07.200 --> 59:13.050] reversing tasks and it is usually a pretty big help in analyzing malware samples. [59:13.920 --> 59:21.420] With this I'm done for today and I'm giving back to the folks from the Blue Team Village.