-
Posts
3453 -
Joined
-
Last visited
-
Days Won
22
Everything posted by Aerosol
-
Download demo Introduction This article explains the code to include the HTML file contents dynamically to the ASPX page. You can download the code and check how it is working. Background I always see this type of requirements asked by members in the Coding Forums. Finally I tried to achieve this. Once, the same thing came to one of my projects, so it also served the purpose. That's why, I am sharing with all of you. It may help you some day. Using the code Step-1: Add Required Controls FileUpload Control to select the HTML File. Upload the file: <asp:FileUpload ID="fileHTMLToBeIncluded" runat="server" /> Button to Upload the file onclick. <asp:Button ID="btnUploadFile" runat="server" Text="Upload HTML File" OnClick="btnUploadFile_Click" /> Literal Control to show the HTML File contents. <asp:Literal ID="ltHTMLBody" runat="server"></asp:Literal> Label to show any Errors/Exceptions. <asp:Label ID="lblError" runat="server"></asp:Label> Step-2: Button Upload Code I will explain the concept. You can refer the whole code by downloading it. Logic Upload and save the File. Open it using File.OpenText Method[^]. And then read to the end of File. Use Regex Class[^](RegularExpression) to get only the body part contents of HTML File. Assign this content to the Literal Control Text Property. Deeper into the Third Step (Regex) Suppose the Hello World HTML file we want to include to ASPX page is something like below. <html> <head> <title> Demo:- Include HTML in Aspx Page </title> </head> <body> <div style="font-family: Verdana; font-size: 20px; color: green; font-weight: bold;"> <label>Hello World!!! From HTML Page.</label> </div> </body> </html> Now we just need to find the contents inside the body tags (here the division). For that, we need to remove texts other than the division. <html> <head> <title> Demo:- Include HTML in Aspx Page </title> </head> <body> <div style="font-family: Verdana; font-size: 20px; color: green; font-weight: bold;"> <label>Hello World!!! From HTML Page.</label> </div> </body> </html> To achieve this, we need two Regular Expressions. First One ( [\s\S]*<body[^<]* ) to match the string before the division start. Second One ( </body[\s\S]* ) to match the string after the division end tag. Let me explain one by one. [\s\S]*<body[^<]*> :- This matches the whole data up to the end of body start tag. Here the first part [\s\S]* will match each and every character before the body start tag. And the whole Regex will match all the characters up to the end of body start tag. So, it will match (which is showing as strike through)... <html> <head> <title> Demo:- Include HTML in Aspx Page </title> </head> <body> <div style="font-family: Verdana; font-size: 20px; color: green; font-weight: bold;"> <label>Hello World!!! From HTML Page.</label> </div> </body> </html> As we get the matched string, we just need to make it blank by using Regex.Replace Method (String, String)[^]. // Replace contents upto start tag of body. start = new Regex(@"[\s\S]*<body[^<]*>", RegexOptions.IgnoreCase); strHTML = start.Replace(strHTML, string.Empty); Now after this coding line, we will have HTML text (strHTML) as below. <div style="font-family: Verdana; font-size: 20px; color: green; font-weight: bold;"> <label>Hello World!!! From HTML Page.</label> </div> </body> </html> </body[\s\S]* :- This Regex will match every character starting from body end tag till the end. <div style="font-family: Verdana; font-size: 20px; color: green; font-weight: bold;"> <label>Hello World!!! From HTML Page.</label> </body> </html> Now, we will follow the same procedure to replace the matched string with blank. // Replace contents from end tag of body. end = new Regex(@"</body[\s\S]*", RegexOptions.IgnoreCase); strHTML = end.Replace(strHTML, string.Empty); After this line, the HTML text (strHTML) will contain the below text. <div style="font-family: Verdana; font-size: 20px; color: green; font-weight: bold;"> <label>Hello World!!! From HTML Page.</label> </div> Last Step Last step is to assign the above division to the Literal Control Text. ltHTMLBody.Text = strHTML; History 03 July 2013 - First version submitted for approval. 29 Dec 2014 - Project Added for Download. Source
-
Download MySpy_exe.zip - 926 KB Download MySpy_sln-noexe.zip - 1 MB Introduction MySpy enumerates windows on the desktop and lists them in a tree. You can see some properties of a window represented by a node in the tree (eg. HWND, PID, ect.) and some more in the info pane. For example the properties of the main window of MySpy: Title : MySpy HWND : 01051258 Class Name : MySpy_MainFrame Class Style : CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS Module Name : N/A Rect : (365, 167)-(1309, 695) 944x528 Window Style : WS_BORDER | ... | WS_TILEDWINDOW | WS_VISIBLE = 349110272 Window ExStyle : WS_EX_OVERLAPPEDWINDOW |...| WS_EX_WINDOWEDGE = 00000264 Process ID : 00000644 Thread ID : 00006988 Window ID : 1351813779 Toolbar functions Set MySpy top most Refresh window tree Filter buttons (filters can be used combined eg. visible & parent windows) visible windows invisible windows parent windows child windows Display numbers in hex Highlight selected window Find ... To find a window by text displayed in the tree or by mouse is also possible. The tool is very handy if you want to find a control, which is hidden, or if its size became 0 for some reason. The user can take several actions on a selected window: Show Hide Enable Disable Left click Right click Left double-click Right double-click Minimize Maximize Close With the Post Message Toolbar you can send or post messages, set text and transparency of the selected window. Background I wrote this program long time ago, but it can be used nowadays too. It helped me to detect bugs, develop tricky controls and impress colleagues they don't even know about WinApi Smile | Points of Interest WinApi is an "old" technology, but it's worth to know about it. History 29/12/2014 1.0 Initial version Source
-
This article tries to create a clear understanding on making synchronous and asynchronous ajax calls through jQuery ajax method. After going through it you can have a clear idea on how and when to do asynchronous ajax calls. Introduction Ajax(Asynchronous Javascript + XML) is a new approach now a days very popular in web development. Ajax taken our classic web development to a different level. It is a new approach to create fast and dynamic web pages.It toally removed the reloading part from the classical web development. Background There are many Ajax methods provided by jQuery library to accomplish ajax calls as listed below :- get post getScript getJSON ajax These all ajax methods can be used as per requirements you are having but, if you need extensive configurability and want to handle errors by yourself then '.ajax()' method is the best. To work with the jQuery ajax method we need to set the options available for it properly, from which 'async' is an important setting about which we are going to discuss here as setting its value will have a major impact in getting response properly. As async is an boolean property, we can set either TRUE or FALSE value for it. Here i will explain various scenarios on setting each values for the particular property(async) and to help you understanding its importance and usability by situation. Using the code Here i am explaining simple examples how and when to make your choice in between asynchronous or synchronous ajax calls using jQuery. Both methods independent of each other :- There will be no impact on result if both are independent whether it is a asynchronous or synchronous ajax calls $(function () { // When both the method are independent & async=false GetData1(false); GetData2(false); // When both the method are independent & async=true GetData1(true); GetData2(true); }); First Method function GetData1(isAsync) { $.ajax({ type: "POST", url: "../WebMethods/WebService.asmx/GetData1", data: "{}", contentType: "application/json; charset=utf-8", dataType: "json", async: isAsync, success: function (response) { var result = JSON.parse(response.d); }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert(errorThrown); } }); } Second Method function GetData2(isAsync) { $.ajax({ type: "POST", url: "../WebMethods/WebService.asmx/GetData2", data: "{}", contentType: "application/json; charset=utf-8", dataType: "json", async: isAsync, success: function (response) { var result = JSON.parse(response.d); }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert(errorThrown); } }); } Second method dependent on first one :- But when second method is dependent on result supplied from first method it will definitely have impact $(function(){ // When second method depends on result of the first method & async=false // If it is a synchronous call then you can get the result from first method before the second method call var result = GetData3(false); // proper result can be found GetData4(false, result); // When second method depends on result of the first method & async=true // If it is an asynchronous call then both the calls will happen asynchrously/simultaneously and you will not // get the result from first method before call of second method as happens in below example var result = GetData3(true); // result will be null here GetData4(true, result); }); First Method function GetData3(isAsync) { var result = null; $.ajax({ type: "POST", url: "../WebMethods/WebService.asmx/GetData3", data: "{}", contentType: "application/json; charset=utf-8", dataType: "json", async: isAsync, success: function (response) { result = JSON.parse(response.d); }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert(errorThrown); } }); return result; } Second Method : Takes an extra argument which is the result of first method. function GetData4(isAsync, result) { $.ajax({ type: "POST", url: "../WebMethods/WebService.asmx/GetData4", data: "{}", contentType: "application/json; charset=utf-8", dataType: "json", async: isAsync, success: function (response) { if (result.id == 1) { var result = JSON.parse(response.d); // do your operation here } else alert('No operation required..'); }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert(errorThrown); } }); } Points of Interest This will definitely of help to the developers who started working on jQuery Ajax method. There are many scenarios and requirements, we need to understand the fundamentals so that we can make right choice one at right place. Source
-
Ti-am lasat pm!
-
Anonymous Declares War on Lizard Squad Hacker Team
Aerosol replied to kp112's topic in Stiri securitate
Anonymous ( pulimea de 10-15 ani) si Lizardsquad ( prostimea de 15 -18 din india) Ce dracu ba nu aveau nimic mai bun decat sa vorbesca despre astia... @DIICOT_VA_SALTA nu cred ca ma cunosti sau ca ai vorbit vre-o data cu mine pe "mess" pe mess am inceput sa intru anul asta prin ianuarie cam asa ( plus ca am folosit mess o scurta perioada de timp ) cat despre tine bravo frate iti faci un cont( presupunand ca esti deja um membru de onoare cu multe cunostiinte in domeniul IT [not]) si mna ca sa nu iei warn pe contul tau hai sa ma dau mare pe alt cont in fine... Felicitari! ( cat despre varsta am 21 daca te intereseaza.) Scuzati-ma pentru offtopicul creat dar a trebuit sa ii raspund! Atentie au venit pe forum anonymous_wanna_be -
So in this blog I've talked many times in-depth regarding postmortem debugging kernel-dumps as far as blue screen crashes goes. Well, I decided maybe it's time to go ahead and actually in detail explain why a blue screen occurs, what actually goes on when a blue screen occurs, etc. -- Disclaimer: At the time of this post, I have never myself experienced a BSOD on my Windows 8.1 system, so I cannot 100% confirm whether or not the display is shifted to a low-res VGA mode when paining the screen. I may use NotMyFault to test this out and will edit when I get a confirmation. For now though, let's assume nothing has changed and hope I'm correct : ) --------------------------- First off, why does the blue screen of death occur? Well, it's important to know that there are many reasons as to why a blue screen occurs. Just to name a few: References to invalid/inaccessible memory; causes access violations, etc. Unexpected exceptions. Bugs in drivers causing a fault in a kernel-mode driver, 3rd party drivers doing what I first mentioned, etc. Again, this is very few of the potential reasons why, but some of the most prevalent. For those interested, here's actually a distribution of what causes bug checks most commonly in Windows. This is a picture I found on Google from a TechNet article, so thanks to the author for this! It's from Windows Internals - 5th Edition. AFAIK there is not one in the 6th, at least I have not seen it throughout my reading or research afterwards. With this said, it's likely not entirely accurate in regards to today, but I imagine it has not changed too much. Given I analyze postmortem kernel-dumps quite a bit, I am surprised to see pool is so low. Again, this was way back in the writing of the 5th edition which was during Vista's legacy, so many things have changed since then. It's up in the air, really! Now, with that said we understand a few reasons as to why Windows stops and a blue screen occurs. Good! Now let's also go ahead and understand that if any of these things occurred, Windows could theoretically not stop and keep going when one of these is occurring. Why doesn't it just do this? Well, it's actually extremely simple, and that's because many of these things can cause severe data/memory corruption which could actually lead to hardware problems. Since we don't want any of that, Windows thankfully has a fail-safe known to us as the Blue Screen of Death (BSOD -- abbreviating from now on). If Windows detects that there is a serious problem that is unrecoverable, it will stop all executions, switch the display to the basic/low-res VGA mode, paint the actual blue screen itself, write memory/crash information to what we know as a memory dump (crash dump/dmp file/dmp), and display a stop code (bug check). All of this is done through a series of functions. Now that we're on this topic, I must STRESS and dispel the misconception right now that the blue screen itself is a bad thing. It's not! The blue screen is a good thing, and it's making it so our data doesn't become completely corrupt. Remember, the blue screen happens because Windows has detected something has gone horribly wrong, and it cannot recover and/or stop it. When this happens, the appropriate bug check based on what caused the error is called, and the blue screen is painted. Bottom line... the blue screen is our friend, not our enemy : ) --------------------------- As discussed above, a blue screen happens when Windows detects that there's an unrecoverable/irreversible problem occurring. Regardless of what this actual problem is, the end result is a blue screen. As I mentioned above, this blue screen process actually happens through functions. Despite the belief that there is only one function that calls and/or begins the bug check process, it is not true! There's two! KeBugCheckEx KeBugCheck Clickable for their MSDN links)! First off, before stating their differences, let's make it easy by saying that both of these functions take what is known as a BugCheckCode parameter. What is a BugCheckCode parameter? Good question! This parameter is otherwise known as a STOP code (for example - 0x0000000A, 0x0000001A, 0x0000009F, etc). These stop codes (otherwise known as/called 'bug checks') are what allows us (other than actually debugging the crash dump itself) to troubleshoot the blue screen. It allows us to go ahead and troubleshoot because each of these STOP codes has an actual preset meaning/cause as to why it occurred. Great, so now that we know that information, what is the difference between KeBugCheckEx and KeBugCheck? Good question! KeBugCheck calls KeBugCheckEx and sets the four parameters to zero. Example - {0,0,0,0} Essentially, the KeBugCheckEx function itself provides more information because it sets the four parameters to their preset meanings based on the STOP code/bug check. --------------------------- Once KeBugCheckEx is called, it first goes ahead and disables all interrupts by calling the KiDisableInterrupts function. After this is done, it transitions to a special system-state in which the STOP code is dumped (0x0000000A for example). It accomplishes the transition and dump of the STOP code with a call from KiDisableInterrupts to the HalDisplayString function. HalDisplayString itself goes ahead and first takes one parameter (string to print to the blue screen), and does a check to see if the system is in its special system-state (blue screen 'mode'). If it is not in this state however, it will go ahead and attempt to successfully use the firmware to swap to this proper system-state in order to continue. Once the check has been successfully completed and confirmed that the system is in its proper state, HalDisplayString goes ahead and dumps the string into text-mode video memory at the current location of the cursor. This is kept track of throughout all of the future calls. After all of this is successfully accomplished, KeBugCheckEx then goes ahead and calls the KeGetBugMessageText function. The KeGetBugMessageText translates the stop code into its text-equivalent. There's a bug check reference list here. Once that is completed, KeBugCheckEx will then go ahead at this point and start to call any bug check handlers that drivers registered (if any). The handlers themselves are registered by calling KeRegisterBugCheckCallback which goes ahead and fills in a buffer that is allocated by the caller of the register routine so it can be debugged in the debugging client. It also essentially in general allows any drivers a chance to stop their devices. Once that is through, we move on to calling the KeRegisterBugCheckReasonCallback function which goes ahead and allows any drivers to write data to the crash dump or write crash dump information to alternate devices. Once the above is done (if possible, because handlers aren't always registered) KeDumpMachineState is called which dumps the rest of the text on the screen. However, the first thing KeDumpMachineState tries to do is successfully interpret the four parameters that were passed to KeBugCheckEx as a valid address within a loaded module. It will go ahead and stop when it can successfully resolve one. The function that is used to accomplish this is KiPcToFileHeader. KiPcToFileHeader returns for the first parameter that it goes ahead and successfully resolves, immediately prints the following text form of the STOP code, and also includes the base address of the module and the module’s name. --------------------------- Below I will share the difference between your standard 8/8.1 and XP/Vista/7 screens: (Windows 8/8.1 displaying 0x5C bug check) Windows XP/Vista/7 displaying 0x50 bug check) Thanks for reading, and thanks to NT Insider and MSDN as always for double-checking! Source
-
Yay, a debugging post! : ) This bug check in most if not all cases is caused by a critical Windows component corruption (.dll, piece of the file system, etc), 3rd party driver causes a conflict (rare), etc. --------------------------- First of all, let's have a look at the basic description of the bug check: WINLOGON_FATAL_ERROR (c000021a) This means that an error has occurred in a crucial user-mode subsystem. Okay, with that said let's go ahead and expand a bit on what this exactly means. Within user-mode we have various subsystems such as WinLogon or csrss.exe (Client/Server Runtime Subsystem). When for some reason these 'critical' subsystems unexpectedly cease to exist, have any sort of problem that prevents them from running or doing their job, the OS will swap to kernel-mode. What's the problem with this? The subsystems I mentioned above are strictly user-mode, therefore when the OS swaps to kernel-mode, it calls a bug check as this is a big no-no as the OS cannot run without those subsystems. In this bug check, two of the four parameters are important: -- In this example, I will be using a 0xC000021A I solved quite some time ago. Your parameters may obviously differ. BugCheck C000021A, {8da5e6b0, c0000006, 75a4e5e5, 13f86c} The 1st parameter (8da5e6b0 in our case) is the string that identifies the problem. The 2nd parameter (c0000006 in our case) is the error code. --------------------------- FAILURE_BUCKET_ID: 0xc000021a_csrss.exe_c0000006_PoShutdown_ANALYSIS_INCONCLUSIVE We can see it was csrss.exe that terminated unexpectedly. Why? 1: kd> db 8da5e6b0 8da5e6b0 57 69 6e 64 6f 77 73 20-53 75 62 53 79 73 74 65 Windows SubSyste 8da5e6c0 6d 00 a5 8d c0 e6 a5 8d-04 04 2b 06 46 4d 66 6e m.........+.FMfn8da5e6d0 04 f2 4e 01 00 00 00 00-a7 73 19 00 00 00 00 00 ..N......s...... 8da5e6e0 e0 e6 a5 8d 00 00 00 00-00 00 00 00 e4 cf 61 8a ..............a. 8da5e6f0 00 00 00 00 00 00 00 00-00 00 00 00 40 00 00 00 ........... @............... 8da5e720 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ If we run db 1st parameter it dumps the bytes from the string. We can see FMFn which is a pool tag, specifically the NAME_CACHE_NODE structure. It's part of fltmgr.sys which is the Microsoft Filesystem Filter Manager driver. 1: kd> da 8da5e6b0 8da5e6b0 "Windows SubSystem" If we run da 1st parameter it dumps ASCII strings. Not very helpful given we already knew this, but it's just another way to show you how you can see what caused the crash. --------------------------- In this specific case, I advised the user to insert the installation media and run a repair (which solved the problem). Thanks for reading! Source
-
Now that my extremely exciting week has come to an end, and I now have a moment to sit and relax, I figured what better way to do that then to go ahead and write a blog post! In this post we'll be discussing the 0x0000119 bug check, otherwise known for its name as VIDEO_SCHEDULER_INTERNAL_ERROR. I worked on one not too long ago, found the thread while I was cleaning out some reference bookmarks, and figured I'd do a write-up! --------------------------- As usual, let's have a look at the basic description of the bug check: VIDEO_SCHEDULER_INTERNAL_ERROR (119) This indicates that the video scheduler has detected a fatal violation. See this MSDN article for more information on Windows video scheduling, memory management, etc. With this out of the way, let's jump right in and have some fun! Using the basic !analyze -v: -- By the way, ! is known as bang. Interesting tidbit of the day : ) VIDEO_SCHEDULER_INTERNAL_ERROR (119) The video scheduler has detected that fatal violation has occurred. This resulted in a condition that video scheduler can no longer progress. Any other values after parameter 1 must be individually examined according to the subtype. Arguments: Arg1: 0000000000000001, The driver has reported an invalid fence ID. Arg2: 0000000000000c00 Arg3: 0000000000000c01 Arg4: 0000000000000c01 Great, so right away we actually have some pretty helpful information, which is the 1st argument tells us that 'The driver has reported an invalid fence ID'. Now that we know this is the reason behind the bug check occurring on the system, we need to understand what driver reported an invalid fence ID, and what a fence ID even is. Regarding arguments 2, 3, and 4, I believe 2 is the invalid fence ID we're dealing with, and 3 & 4 are what the expected fence ID was. First off, we need to understand the Windows Display Driver Model (WDDM) - Article here. After reading this, we can understand that a fence ID is essentially a glorified ticket for the GPU to have access to process a Direct Memory Access (DMA) buffer. This is done so the GPU itself doesn't have to bother the CPU or OS, and its life is a lot easier. --------------------------- Now that we know the above, let's take a look at the call stack: 0: kd> k Child-SP RetAddr Call Site fffff800`04438528 fffff880`015ed22f nt!KeBugCheckEx fffff800`04438530 fffff880`07807ec5 watchdog!WdLogEvent5+0x11b fffff800`04438580 fffff880`07808131 dxgmms1!VidSchiVerifyDriverReportedFenceId+0xad fffff800`044385b0 fffff880`07807f82 dxgmms1!VidSchDdiNotifyInterruptWorker+0x19d fffff800`04438600 fffff880`078f513f dxgmms1!VidSchDdiNotifyInterrupt+0x9e fffff800`04438630 fffff880`073d64d8 dxgkrnl!DxgNotifyInterruptCB+0x83 <--- DMA buffer completed. fffff800`04438660 fffffa80`08d938e8 igdkmd64+0x1744d8 fffff800`04438668 fffff800`031f4e80 0xfffffa80`08d938e8 fffff800`04438670 fffff800`04438840 nt!KiInitialPCR+0x180 fffff800`04438678 fffffa80`0923d7a8 0xfffff800`04438840 fffff800`04438680 fffffa80`0925b000 0xfffffa80`0923d7a8 fffff800`04438688 fffffa80`00000c00 0xfffffa80`0925b000 fffff800`04438690 fffff880`0c52b000 0xfffffa80`00000c00 fffff800`04438698 00000000`00000000 0xfffff880`0c52b000 Essentially what happened here was after the GPU finished processing the DMA buffer, the Intel Graphics driver (igdkmd64.sys) was notified that it finished what is was doing and provided an ID # of the DMA Buffer (known as a fence ID). In our case, this was in invalid fence ID, therefore DirectX said 'woah, this isn't right' and called the bug check to stop the GPU from continuing with illegal accessed memory. --------------------------- With such an issue you may think that it's always a bad GPU, however, in this specific case it was simply a video driver issue that was solved with an update. Update those video drivers! Hope you enjoyed reading! Source
-
I've discussed some 0xD1 debugging here, but I figured I'd also go into a different 0xD1 scenario here, and just show it from different angles by using NotMyFault to force a bug check. Download NotMyfault here. -------------------- DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1) This indicates that a kernel-mode driver attempted to access pageable memory at a process IRQL that was too high. We're all familiar with this bug check, so let's move on to what I wanted to talk about. Let's go ahead and do an !analyze -v DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1) An attempt was made to access a pageable (or completely invalid) address at an interrupt request level (IRQL) that is too high. This is usually caused by drivers using improper addresses. If kernel debugger is available get stack backtrace. Arguments: Arg1: fffff8a0066eb800, memory referenced Arg2: 0000000000000002, IRQL Arg3: 0000000000000000, value 0 = read operation, 1 = write operation Arg4: fffff88002af7385, address which referenced memory fffff8a0066eb800 was the memory that was referenced. It's either invalid or it was at an IRQL that was too high. kd> !pte fffff8a0066eb800 VA fffff8a0066eb800 PXE at FFFFF6FB7DBEDF88 PPE at FFFFF6FB7DBF1400 PDE at FFFFF6FB7E280198 PTE at FFFFF6FC50033758 contains 000000007AC84863 contains 000000000367B863 contains 000000006B4C6863 contains 00003B5000000000 pfn 7ac84 ---DA--KWEV pfn 367b ---DA--KWEV pfn 6b4c6 ---DA--KWEV not valid PageFile: 0 Offset: 3b50 Protect: 0 Using our handy !pte command which shows page table and directory entry for an address, we can see that it is not a valid address despite appearing to be one based on a first glance. Why is it not valid? As we can see above, and as I highlighted in purple, it's because this address is currently on the pagefile. Why can't we just page it in? As we know, this is not how the Windows memory manager works regarding kernel-mode and its rules. If we're at IRQL (2) or higher (which we are, see argument 2), we cannot page anything in, therefore we bug check. Great, so we know why the system crashed. However, what caused it? -------------------- Let's go ahead and dump the stack: kd> k Child-SP RetAddr Call Site fffff880`032f4448 fffff800`02a912a9 nt!KeBugCheckEx fffff880`032f4450 fffff800`02a8ff20 nt!KiBugCheckDispatch+0x69 fffff880`032f4590 fffff880`02af7385 nt!KiPageFault+0x260 fffff880`032f4720 fffff880`02af7727 myfault+0x1385 fffff880`032f4870 fffff800`02dac127 myfault+0x1727 fffff880`032f48d0 fffff800`02dac986 nt!IopXxxControlFile+0x607 fffff880`032f4a00 fffff800`02a90f93 nt!NtDeviceIoControlFile+0x56 fffff880`032f4a70 00000000`76df138a nt!KiSystemServiceCopyEnd+0x13 00000000`0023edc8 00000000`00000000 0x76df138a So here we have our call stack. Rather than doing <--- next to the calls, I'll just do this below because I don't want to destroy the formatting of the stack. We start out with something in user-mode that we don't have the symbols for, and this is why it's 0x76df138a as opposed to a resolved name that we can understand. Why did I make the 7 in the address red, and how did I know we started out with something going on in user-mode? Good question! When the first digit of an address like that is 7 or lower, it's a user-mode address. This is also due to the fact that this is a kernel-dump, which we can see towards the top of our crash dump within WinDbg: Kernel Summary Dump File: Only kernel address space is available With that said, we cannot see what the application was doing outside of when it went down into kernel-mode. So we know that some application (0x76df138a) did something, and called down into kernel-mode. Everything above 0x76df138a is now kernel-mode. On x64, you can tell because the addresses start with fffff880`032f4a00 under Child-SP which implies kernel-mode. We can see it goes through a few functions, and then ends up in myfault. Shortly afterwards, we hit a pagefault (trying to page in memory from the pagefile -- big no no). -------------------- If we take a look at the trap frame: kd> .trap 0xfffff880032f4590 NOTE: The trap frame does not contain all registers. Some register values may be zeroed or incorrect. rax=0000000005000000 rbx=0000000000000000 rcx=0000000000002481 rdx=fffffa8001810000 rsi=0000000000000000 rdi=0000000000000000 rip=fffff88002af7385 rsp=fffff880032f4720 rbp=fffff880032f4b60 r8=0000000000012408 r9=0000000000000810 r10=fffff80002a12000 r11=0000000000000002 r12=0000000000000000 r13=0000000000000000 r14=0000000000000000 r15=0000000000000000 iopl=0 nv up ei ng nz na po nc myfault+0x1385: fffff880`02af7385 8b03 mov eax,dword ptr [rbx] ds:00000000`00000000=???????? The first very important thing to note is the note about the trap frame not containing all registers, and how they may be either zeroed out or incorrect. The big question is why? Well, trap frame code generation on x64 versions of Windows does not save the contents of registers that are non-volatile. With that said, registers such as rbx, rdi, rsi, etc, are either zeroed out or incorrect. This is due to the fact that on x64, any code that runs after the generation of a trap frame will properly hand it and restore it to its own frame. It's seen as an unnecessary step in a hot path within the kernel. Extremely detailed article with much more info here. Moving on, what happened with the instruction we failed on, we were moving a pointer which was stored in the rbx register: mov eax,dword ptr [rbx] Uh oh, rbx is zeroed out. With that said, we can't !pte the register address to double check it, etc. We just need to assume that this all occurred because of myfault attempted to access memory that was either paged out or invalid (which it did). -------------------- If you wanted any extra proof or to see if NotMyFault was the crash, you could dump all of the processes at the time of the crash to see if there was any correlation. In this case, you'd use !process 0 0. Flags are important in this case, and you can as always check the WinDbg help file for info, or use MSDN. PROCESS fffffa80040a7060 SessionId: 1 Cid: 0654 Peb: 7fffffd4000 ParentCid: 0708 DirBase: 670ea000 ObjectTable: fffff8a00666c330 HandleCount: 68. Image: NotMyfault.exe We can see we did indeed have a NotMyFault process running at the time of the crash, so we can at this point assume that this is very likely the accurate cause of the crash. Hope you enjoyed reading! Source
-
You know when you have something you really want to write a blog post about, but you don't have a crash dump for it? Debugger problems. Fortunately enough for me, I searched Google for a live crash dump link and found one. Happy days! Thanks to this person from four or so years ago for their crash dump :~) Let's take a look at our basic bug check information in this case. This time, let's use code boxes. I never use code boxes on my blog, but now it's time! SYSTEM_SERVICE_EXCEPTION (3b) An exception happened while executing a system service routine. Arguments: Arg1: 00000000c0000005, Exception code that caused the bugcheck Arg2: fffff80002cc272d, Address of the instruction which caused the bugcheck Arg3: fffff8800a555070, Address of the context record for the exception that caused the bugcheck Arg4: 0000000000000000, zero. As with most 0x3B's, our exception was specifically an access violation. 2: kd> ln fffff80002cc272d (fffff800`02cc2590) nt!KiDpcInterrupt+0x19d | (fffff800`02cc2780) nt!KiDpcInterruptBypass The violation in this case specifically occurred in nt!KiDpcInterrupt+0x19d. 2: kd> .cxr 0xfffff8800a555070;r rax=0000000000000001 rbx=fffffa8006b24b60 rcx=0000000000000000 rdx=000001af00000000 rsi=0000000000000000 rdi=0000000000000003 rip=fffff80002cc272d rsp=fffff8800a555a50 rbp=fffff8800a555ad0 r8=0000000000000000 r9=0000000000000001 r10=0000000000000000 r11=0000000000000064 r12=0000000000000000 r13=0000000000000000 r14=0000000000000064 r15=000007ff00042020 iopl=0 nv up di pl zr na po nc cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00010046 nt!KiDpcInterrupt+0x19d: fffff800`02cc272d 0fae1f stmxcsr dword ptr [rdi] ds:002b:00000000`00000003=???????? On the instruction we faulted on, we failed storing the contents of the MXCSR register within rdi (0000000000000003). We can certainly imagine 00000000`00000003 is completely invalid, so therein lies our problem. So, why are we hitting a pagefault within a DPC interrupt? Good question! Let's run the following: !chkimg -lo 50 -db -v !nt !chkimg compares an image with its original copy. More specifically, it does this by comparing the image of an executable file in memory to the copy of the file that resides on a symbol store. The -lo 50 parameter limits the number of output lines to 50. Not too much and not too little. The -db parameter displays mismatched areas in a format that is similar to the db debugger command. Therefore, each display line shows the address of the first byte in the line, followed by up to 16 hexadecimal byte values. The byte values are immediately followed by the corresponding ASCII values. All nonprintable characters, such as carriage returns and line feeds, are displayed as periods (.). The mismatched bytes are marked by an asterisk . The -v parameter displays extra verbose information. !nt is the module, which is of course the kernel. 2: kd> !chkimg -lo 50 -db -v !nt Searching for module with expression: !nt Will apply relocation fixups to file used for comparison Will ignore NOP/LOCK errors Will ignore patched instructions Image specific ignores will be applied Comparison image path: c:\localsymbols\ntkrnlmp.exe\4A5BC6005dd000\ntkrnlmp.exe No range specified Above we can see that as I noted above, it's comparing the kernel image from the crash dump to the latest symbol stored on my local symbol cache. If it wasn't available locally, it'd grab it from the symbol server. Scanning section: .text Size: 1685025 Range to scan: fffff80002c06000-fffff80002da1621 Total bytes compared: 1685025(100%) Number of errors: 40 So we have 40 errors specifically in the .text section of the kernel that was scanned. fffff80002cc2680 19 b9 01 00 00 00 44 *44 22 c1 fb e8 80 17 f9 *48 ......DD"......H fffff80002cc2690 fa b9 00 00 00 00 44 *45 22 c1 65 48 8b 0c 25 *34 ......DE".eH..%4 fffff80002cc26a0 01 00 00 f7 01 00 00 *25 40 74 25 f6 41 02 02 *85 .......%@t%.A... fffff80002cc26b0 0e e8 8a 68 05 00 65 *8b 8b 0c 25 88 01 00 00 *48 ...h..e...%....H ... fffff80002cc2700 8b 55 d8 4c 8b 4d d0 *ba 8b 45 c8 48 8b 55 c0 *00 .U.L.M...E.H.U.. fffff80002cc2710 8b 4d b8 48 8b 45 b0 *07 8b e5 48 8b ad d8 00 *89 .M.H.E....H..... fffff80002cc2720 00 48 81 c4 e8 00 00 *ff 0f 01 f8 48 cf 0f ae *1f .H.........H.... fffff80002cc2730 ac 0f 28 45 f0 0f 28 *4c 00 0f 28 55 10 0f 28 *40 ..(E..(L..(U..(@ ... fffff80002cc2880 24 10 48 89 74 24 18 *38 89 64 24 20 48 8b f9 *00 $.H.t$.8.d$ H... fffff80002cc2890 8b d1 49 8b f0 4c 8b *15 49 83 e9 11 48 83 ea *01 ..I..L..I...H... fffff80002cc28a0 4c 8b da 48 8b ef bb *8b 00 00 00 49 3b f1 0f *48 L..H.......I;..H fffff80002cc28b0 c1 05 00 00 49 3b fb *48 83 b8 05 00 00 8a 06 *e8 ....I;.H........ ... fffff80002cc2900 a8 20 0f 85 e6 03 00 *90 8a 56 06 88 57 05 a8 *44 . .......V..W..D fffff80002cc2910 0f 85 69 04 00 00 8a *41 07 88 57 06 a8 80 0f *ec ..i....A..W..... fffff80002cc2920 db 04 00 00 8a 56 08 *f9 57 07 48 83 c6 09 48 *ba .....V..W.H...H. fffff80002cc2930 c7 08 e9 74 ff ff ff *24 3b fd 0f 87 b8 00 00 *05 ...t...$;....... ... fffff80002cc2980 f3 a4 49 8b f4 48 83 *8b 01 a8 02 0f 85 81 00 *83 ..I..H.......... fffff80002cc2990 00 8a 56 02 88 57 01 *49 04 0f 85 40 01 00 00 *f2 ..V..W.I.. @.... fffff80002cc29a0 56 03 88 57 02 a8 08 *3a 85 f1 01 00 00 8a 56 *48 V..W...:......VH fffff80002cc29b0 88 57 03 a8 10 0f 85 *00 02 00 00 8a 56 05 88 *8b .W..........V... Assuming I am correct (which I hopefully am), every 8th and 16th bit of each byte are no good (as if it's striding through the data). This is known as a stride corruption pattern. MEMORY_CORRUPTOR: STRIDE It's a characteristic of address line issues that occur somewhere between going in/out of RAM. Despite the display evidence thus far, we cannot jump to a faulty RAM conclusion as much as we'd like to. Perhaps we'd like to assume that the selector which controls these lines is faulty, so any byte stored in these lines is going to have invalid 8th and 16th bits. This would mean faulty RAM, however, in debugging we must always be sure to check everything before doing something such as outright replacing the RAM, even though we could defend and say that a Memtest would be just fine as well. A similar memory corruption pattern is misaligned IP (instruction pointer). Not going into that in this blog post, but it's also another one you need to be 100% sure is not a simple buffer overflow as opposed to faulty RAM. Do note that WinDbg is not smarter than we are and assumes that a misaligned IP is a hardware problem. Enough blabbering, onto what I am trying to get to... PROCESS_NAME: MOM.exe MOM.exe, what are you doing here? By the way, MOM.exe is AMD/ATI's Catalyst Control Center (CCC) monitoring software. It's not malware, or an actual mother. </badjoke> You normally don't see this process involved with a crash too often, and with this said, I did some digging in the modules list to see if any 3rd party software may have caused conflicts. 2: kd> lmvm rtcore64 start end module name fffff880`0859b000 fffff880`085a1000 RTCore64 (deferred) Image path: \??\C:\Program Files (x86)\MSI Afterburner\RTCore64.sys Image name: RTCore64.sys Timestamp: Wed May 25 02:39:12 2005 Oh my... MSI AB driver from 2005 on an x64 Windows 7 box! The horror. So, today's lesson summed up is - If you're going to actually use MSI Afterburner (the horror), be sure to keep it up to date so you don't upset mother <\badjoke> and make her crash by causing stride corruption. Thanks for reading! Source
-
I was recently sent a pretty neat kernel-dump by my good friend Jared. I've always wanted to go into double faults, so let's get started! Thanks, Jared : ) UNEXPECTED_KERNEL_MODE_TRAP (7f) This means a trap occurred in kernel mode, and it's a trap of a kind that the kernel isn't allowed to have/catch (bound trap) or that is always instant death (double fault). Arguments: Arg1: 0000000000000008, EXCEPTION_DOUBLE_FAULT Arg2: 0000000080050033 Arg3: 00000000000406f8 Arg4: fffff800032aa875 In our case, the 1st argument was 8, therefore this indicates a double fault occurred. So, what is a double fault, and when/why does one occur? Double faults occur when an exception cannot be handled by the handler, or when an exception occurs when the CPU is already trying to call an exception handler for a previously thrown exception. In most cases, two exceptions that were thrown at the exact same time are handled separately, however in some cases, you may have a situation occur in which a pagefault occurs, but the exception handler is located in a not-present page, two page faults would occur and neither of them can be handled. This is known as a double fault! Also, double faults can occur (like in this scenario) when the processor cannot properly service an interrupt that is pending. 4: kd> k Child-SP RetAddr Call Site fffff880`009b9de8 fffff800`0328b169 nt!KeBugCheckEx fffff880`009b9df0 fffff800`03289632 nt!KiBugCheckDispatch+0x69 fffff880`009b9f30 fffff800`032aa875 nt!KiDoubleFaultAbort+0xb2 <- Uh oh, double fault! fffff880`03dccfd0 fffff800`032909ba nt!KiIpiSendRequest+0x305 <- As it is a multiprocessor job, processor #4 sent an inter-processor interrupt to interrupt another processor saying "Hey, we need to flush the TLB." fffff880`03dcd090 fffff800`032ec198 nt!KeFlushMultipleRangeTb+0x22a <- Flushing translation lookaside buffer, this is a multiprocessor job. fffff880`03dcd160 fffff800`033935ea nt! ?? ::FNODOBFM::`string'+0x204ce fffff880`03dcd350 fffff800`03394be7 nt!MiEmptyWorkingSet+0x24a <- Removing as many pages as possible from the working set. fffff880`03dcd400 fffff800`0372f371 nt!MiTrimAllSystemPagableMemory+0x218 <- Unmapping all pageable system memory. fffff880`03dcd460 fffff800`0372f4cf nt!MmVerifierTrimMemory+0xf1 fffff880`03dcd490 fffff800`0372fc24 nt!ViKeRaiseIrqlSanityChecks+0xcf <- As verifier is enabled, it's doing a sanity check. A sanity check is essentially verifier saying "Okay, what IRQL are we on and are we supposed to be here?" fffff880`03dcd4d0 fffff880`018443f5 nt!VerifierKeAcquireSpinLockRaiseToDpc+0x54 <- IRST resetting IRQL to DISPATCH (2) and then acquiring a lock. fffff880`03dcd530 fffff880`018222a2 iaStor+0x253f5 <- Intel Rapid Storage Technology fffff880`03dcd560 fffff880`01871489 iaStor+0x32a2 <- Intel Rapid Storage Technology 4: kd> ub nt!KiIpiSendRequest+0x305 nt!KiIpiSendRequest+0x2eb: fffff800`032aa85b 5e pop rsi fffff800`032aa85c 5d pop rbp fffff800`032aa85d c3 ret fffff800`032aa85e 8bc6 mov eax,esi fffff800`032aa860 e9e2feffff jmp nt!KiIpiSendRequest+0x1d7 (fffff800`032aa747) fffff800`032aa865 0fb70db4892100 movzx ecx,word ptr [nt!KeActiveProcessors (fffff800`034c3220)] fffff800`032aa86c 0fb705af892100 movzx eax,word ptr [nt!KeActiveProcessors+0x2 (fffff800`034c3222)] fffff800`032aa873 8bfa mov edi,edx By unassmembling nt!KiIpiSendRequest+0x305 backwards, it looks like there's a check for active processors, and then the attempt to send the IPI. 4: kd> !ipi IPI State for Processor 0 TargetCount 0 PacketBarrier 0 IpiFrozen 2 [Frozen] IPI State for Processor 1 TargetCount 0 PacketBarrier 0 IpiFrozen 2 [Frozen] IPI State for Processor 2 TargetCount 0 PacketBarrier 0 IpiFrozen 2 [Frozen] IPI State for Processor 3 TargetCount 0 PacketBarrier 0 IpiFrozen 2 [Frozen] IPI State for Processor 4 TargetCount 0 PacketBarrier 0 IpiFrozen 0 [Running] IPI State for Processor 5 TargetCount 0 PacketBarrier 0 IpiFrozen 2 [Frozen] IPI State for Processor 6 TargetCount 0 PacketBarrier 0 IpiFrozen 2 [Frozen] IPI State for Processor 7 TargetCount 0 PacketBarrier 0 IpiFrozen 2 [Frozen] By running !ipi we can check the inter-processor interrupt state for every processor on the box. We can see here that every single processor (except #4) is in a frozen state (idle), therefore obviously our IPI is never going to be serviced, will remain pending, and we're going to double fault. 4: kd> lmvm iaStor start end module name fffff880`0181f000 fffff880`01bc3000 iaStor (no symbols) Loaded symbol image file: iaStor.sys Image path: \SystemRoot\system32\DRIVERS\iaStor.sys Image name: iaStor.sys Timestamp: Wed Feb 01 19:15:24 2012 The IRST driver is dated from early 2012, which is likely the problem since it is a notoriously problematic driver, and it gets worse as it gets older. The newer update would likely solve it, but honestly, I always usually recommend a user safely removes and replaces this driver with the standard MSFT driver if they aren't running a RAID setup. Kaspersky was also present on this system, and antivirus suites don't tend to play nice with this software either. This post also shows how helpful Driver Verifier is, and how without it in this specific scenario, we likely would have had no idea what was causing this, and may interpret it as a hardware problem. Thanks for reading! Source
-
I received a PDC_WATCHDOG_TIMEOUT (14f) crash dump, although I seemed to have misplaced the source. What a shame! Anyway, this bug check is pretty mysterious. There's very little to no documentation on it, and not too many have had it occur on their systems to show up in any sort of web search. With that said, let's do our best to get some info on it! PDC_WATCHDOG_TIMEOUT (14f) A system component failed to respond within the allocated time period, preventing the system from exiting connected standby. Arguments: Arg1: 0000000000000002, Client ID of the hung component. Arg2: 0000000000000002, A resiliency client failed to respond. Arg3: fffff801867d3578, Pointer to the resiliency client (pdc!_PDC_RESILIENCY_CLIENT). Arg4: ffffd001b7f61b30, Pointer to a pdc!PDC_14F_TRIAGE structure. We can see right away that the cause of the bug check itself is: A system component failed to respond within the allocated time period, preventing the system from exiting connected standby. With that said, now is a good time to discuss connected standby. Connected standby is a low-power state (implemented in Windows 8, also in 8.1) that features extremely low power consumption while maintaining a constant internet connection. Here is how to trigger connected standby: Press the system power button. Close the lid or tablet cover, or close the tablet into an attached dock. Select Sleep from the Power button on the Settings charm The best comparison is a smartphone's power button. When you press the power button on one of today's smartphones, it will transition to a similar state as opposed to entirely shutting down. This way, when you press the power button again, it will start right back up from where you previously left off. Now that we know how to trigger the connected standby, how does it wake up and transition to its active state again? Press the system power button. Open the lid on a clamshell form-factor system. Open the tablet if it is connected to a portable dock with a keyboard (similar to a lid in a clamshell system). Generate input on an integrated or attached keyboard, mouse, or touchpad. Press the Windows button that is integrated into the system display. Other than user-related actions, system components, programs, etc, can wake the system from connected standby as well. For example, if the user has an incoming Skype call, the system will immediately awake and create a 25 second time frame to answer the call. If it is not answered, the call is canceled and the system will go back into connected standby. System components or devices can also wake the core silicon or SoC from connected standby, even though those events may not turn on the display. Nearly all devices connected to a connected standby system are expected to be capable of waking the SoC from its deepest idle power state. -------------------- Now that we understand connected standby, we now understand that for some reason a specific system component failed to respond during the set time period, therefore the system remained in connected standby when it should have woken up. First of all, what kind of device is this given the fact that we likely wouldn't see connected standby on a desktop (or maybe even a laptop)? 0: kd> !sysinfo machineid Machine ID Information [From Smbios 2.8, DMIVersion 39, Size=1106] BiosMajorRelease = 3 BiosMinorRelease = 7 FirmwareMajorRelease = 32 FirmwareMinorRelease = 0 BiosVendor = American Megatrends Inc. BiosVersion = 3.07.0150 BiosReleaseDate = 05/15/2014 SystemManufacturer = Microsoft Corporation SystemProductName = Surface Pro 3 SystemFamily = Surface SystemVersion = 1 SystemSKU = Surface_Pro_3 BaseBoardManufacturer = Microsoft Corporation BaseBoardProduct = Surface Pro 3 BaseBoardVersion = 1 Ah, it's a Surface tablet! It all makes sense now. As this was a minidump, our call stack was extremely uninformative: 0: kd> k Child-SP RetAddr Call Site ffffd001`b7f61af8 fffff801`867dcd72 nt!KeBugCheckEx ffffd001`b7f61b00 fffff803`712daadb pdc!PdcpResiliencyWatchdog+0xa6 ffffd001`b7f61b50 fffff803`71356794 nt!ExpWorkerThread+0x293 ffffd001`b7f61c00 fffff803`713e15c6 nt!PspSystemThreadStartup+0x58 ffffd001`b7f61c60 00000000`00000000 nt!KiStartSystemThread+0x16 We can see we're starting a thread which turns out to be a worker thread, and then we call into pdc!PdcpResiliencyWatchdog+0xa6. This implies we failed to complete the resiliency phase in the allotted time period (however long). Usually when you see resiliency phase issues on a device regarding anything in terms of waking from an inactive state (sleep, hibernate, etc), the first thing to look at is network. For example, the D0 IRP for the required network device may not have completed in time due to a 3rd party conflict, etc. We can further confirm we're likely dealing with a network issue by taking a look at our bucket_id: FAILURE_BUCKET_ID: 0x14F_WCM_pdc!PdcpResiliencyWatchdog WCM is the Windows Connection Manager, which enables the creation and configuration of connection manager software. As this is a Surface Tablet, one can imagine it's likely using WiFi. If a Wi-Fi connection is available, the system will wait for the Wi-Fi device only, regardless of whether a mobile broadband (MBB) connection is available. With this said, I took a look at what loaded modules we had to see if any antivirus was installed, firewall, etc. I was essentially looking for anything that could have accidentally interfered with the network upon wake. Here's what I found: 0: kd> lmvm MBAMSwissArmy start end module name fffff801`8851d000 fffff801`8853e000 MBAMSwissArmy (deferred) Image path: \??\C:\windows\system32\drivers\MBAMSwissArmy.sys Image name: MBAMSwissArmy.sys Timestamp: Thu Mar 20 18:12:35 2014 Malwarebytes Anti-malware driver, listed and loaded. I asked the user to uninstall Malwarebytes for temporary troubleshooting purposes, and the crashes no longer occurred. I hope the user also contacted Malwarebytes support to work out any possible issues that need to be patched. I hope to see more of these bug checks in the future, and hopefully with a kernel-dump next time as well so I can go in-depth! Thanks for reading! Source
-
Today we're going to be doing some rootkit debugging, specifically regarding runtime2, with a bit of a twist! I have a ton of rootkit debugging posts coming in the next few weeks, as I've decided to break them up rather than throwing them together in one giant mess of a post. I've shown various scenarios in which I've debugged a rootkit before (0x7A, etc), but this time we're going to use various extensions to help us, other methods, and overall go a lot more in-depth. The postmortem runtime2 rootkit KMD that will be used in this post was generated by niemiro, a good friend from Sysnative forums. He aimed to make it a good example of some things a rootkit/malware developer can do to make things not as obvious when you resort to methods such as hooking the SSDT, which is rather old and very detectable these days. CRITICAL_OBJECT_TERMINATION (f4) A process or thread crucial to system operation has unexpectedly exited or been terminated. Several processes and threads are necessary for the operation of the system; when they are terminated (for any reason), the system can no longer function. Arguments: Arg1: 00000003, Process Arg2: 86664d90, Terminating object Arg3: 86664edc, Process image file name Arg4: 819e91f0, Explanatory message (ascii) Right, so here's our bug check. Most if not all of these 'older' rootkits will use Direct Kernel Object Manipulation (DKOM) to hook low-level routines/functions within the System Service Dispatch Table (SSDT). When this is occurring, assuming the developer of the rootkit didn't do a very good job in writing their rootkit, a lot can go wrong when disabling write protection, carelessly swapping memory, and inserting hooks. Malware scans from many AV programs can also cause crashes when they detect that the SSDT is hooked under certain circumstances. The rootkit can also intentionally call a bug check if written this way when it has detected a scan has initiated. However, if the driver is well written, you may not crash at all. What do you do if you're suspicious of a rootkit infection/hooking, yet a bug check isn't occurring naturally due to proper programming of the rootkit? This is when in some cases (like in this specific example here), you may need to take matters into your own hands and either: Force a bug check. Live kernel debugging session. Run an ARK (Anti-Rootkit) tool. This is no fun... we want to have fun and learn : ) The first option is much less effective than the second, and that's due to the fact that the rootkit may not be doing any obvious hooking of the SSDT, etc, at the time of you forcing the crash. If you're investigating during a live session, it's much more effective and there are a lot more commands you can use. However, for learning purposes, I will show both. 1st argument - The value in the 2nd argument (0x3) implies it was a process as opposed to a thread that unexpectedly terminated. If it was a thread however, it would have instead been 0x6. 2nd argument - The value in the 2nd argument (86664d90) is a pointer to the _EPROCESS object that unexpectedly terminated. We can dump it using !object, which I will show below: kd> !object 86664d90 Object: 86664d90 Type: (841537e8) Process ObjectHeader: 86664d78 (old version) HandleCount: 4 PointerCount: 127 3rd argument - The value in the 3rd argument (86664edc) is the process image file name. Essentially, it's the process name that unexpectedly terminated. We can dump it by using dc, which I will show below: kd> dc 86664edc 86664edc 73727363 78652e73 00000065 00000000 csrss.exe....... 86664eec 00000000 00000000 00000000 8605a278 ............x... 86664efc 869356d8 00000000 00000000 0000000a .V.............. 86664f0c 8c04d631 00000000 00000000 7ffdc000 1............... 86664f1c 00000000 00000099 00000000 00000000 ................ 86664f2c 00000000 000005c6 00000000 0003cc50 ............P... 86664f3c 00000000 00000000 00000000 00006d77 ............wm.. 86664f4c 00000000 00000000 00000162 00000000 ........b....... The process that unexpectedly terminated was csrss.exe, which is the Client/Server Runtime Subsystem. For some extra food for thought, we can get a lot of the information above manually if we'd like to. If we take the 2nd argument (_EPROCESS object) and run the following: dt _EPROCESS 86664d90 imageFileName dt will display the type, which will show us the offset, etc. More specifically it displays information about a local variable, global variable or data type: kd> dt _EPROCESS 86664d90 imageFileName nt!_EPROCESS +0x14c ImageFileName : [16] "csrss.exe" If we take the _EPROCESS object and add it to the offset (+0x14c), we get the following: kd> ? 86664d90+0x14c Evaluate expression: -2040115492 = 86664edc Look familiar? It's our 3rd argument, the process image name (csrss.exe). 4th argument - The value in the 3rd argument (819e91f0) is the explanatory message regarding the reason for the bug check, specifically in ASCII. To dump this, we'll need to use the dc command as we used earlier on the 3rd argument: kd> dc 819e91f0 819e91f0 6d726554 74616e69 20676e69 74697263 Terminating crit 819e9200 6c616369 6f727020 73736563 25783020 ical process 0x% As we can see, this is reiterating the 1st argument. -------------------- So far all we know is that this bug check occurred because csrss.exe, a critical Windows process, unexpectedly terminated. Why? If you weren't able to tell whilst reading through by now, we purposely terminated it via Task Manager to force the bug check.With that said, for this post we're choosing the first method (forcing a bug check). Pretending we ourselves didn't purposely force the bug check for a moment, what would we at this point do if this was a crash dump we were looking at from a system that isn't ours, and/or from our doing? Among many things, one of the first few things I do in 'not so obvious' 0xF4's is I check the summary and stats regarding virtual memory on the system at the time of the crash: kd> !vm *** Virtual Memory Usage *** Physical Memory: 917370 ( 3669480 Kb) Page File: \??\C:\pagefile.sys Current: 3976680 Kb Free Space: 3976676 Kb Minimum: 3976680 Kb Maximum: 4193280 Kb Available Pages: 769568 ( 3078272 Kb) ResAvail Pages: 869504 ( 3478016 Kb) Locked IO Pages: 0 ( 0 Kb) Free System PTEs: 348283 ( 1393132 Kb) Modified Pages: 11884 ( 47536 Kb) Modified PF Pages: 11830 ( 47320 Kb) NonPagedPool Usage: 8265 ( 33060 Kb) NonPagedPool Max: 522998 ( 2091992 Kb) PagedPool 0 Usage: 5501 ( 22004 Kb) PagedPool 1 Usage: 10013 ( 40052 Kb) PagedPool 2 Usage: 623 ( 2492 Kb) PagedPool 3 Usage: 631 ( 2524 Kb) PagedPool 4 Usage: 726 ( 2904 Kb) PagedPool Usage: 17494 ( 69976 Kb) PagedPool Maximum: 523264 ( 2093056 Kb) Session Commit: 3758 ( 15032 Kb) Shared Commit: 9951 ( 39804 Kb) Special Pool: 0 ( 0 Kb) Shared Process: 1260 ( 5040 Kb) Pages For MDLs: 2 ( 8 Kb) PagedPool Commit: 17550 ( 70200 Kb) Driver Commit: 2335 ( 9340 Kb) Committed pages: 115256 ( 461024 Kb) Commit limit: 1882649 ( 7530596 Kb) We can see right away that we don't have insufficient non-paged pool, which is a pretty popular cause of most 0xF4's as it at that point cannot handle I/O operations, etc. It's generally due to buggy drivers causing pool related memory leaks, etc. With the above said, assuming we are looking at a crash dump that wasn't ours, we can almost entirely rule out this specific 0xF4 being caused by a buggy driver (MSFT or 3rd party). To be extra sure, double-check the modules list and see if there's anything that jumps out as problematic. -------------------- At this point I would start becoming suspicious of a rootkit, as I would not right away suggest the hard disk (whether HDD or SSD) is the immediate problem given we'd probably see obvious NT_STATUS codes for that. For example, possibly 0xc0000006. Either that, or an entirely different bug check (perhaps 0x7A). With that said, now we get to have some fun! There are many ways to go about detecting a rootkit hooking the SSDT, and we will discuss extensions/scripts for the moment: 1st Method - SwishDbgExt The first method we will be using in this postmortem debugging example is the wonderful SwishDbgExt, which was developed/created by a friend of mine (Matt Suiche). I've made various contributions to the help file considering the love I have gathered for this extension. It makes a lot of our lives as debuggers much easier. Once you have the extension loaded, we're going to be using the !ms_ssdt command. This command displays the System Service Dispatch Table, which is extremely helpful in the investigation of suspected rootkit hooks through using what is known as Direct Kernel Object Manipulation (DKOM). -- Chopping some of the SSDT output as it's fairly large, let's skip to what's important: |-------|--------------------|--------------------------------------------------------|---------|--------| | Index | Address | Name | Patched | Hooked | |-------|--------------------|--------------------------------------------------------|---------|--------| *** ERROR: Module load completed but symbols could not be loaded for Gjglly.sys | 126 | 0xFFFFFFFF91F054C2 | Gjglly | | | | 127 | 0xFFFFFFFF81A34F80 | nt!NtDeviceIoControlFile | | | | 128 | 0xFFFFFFFF81949B44 | nt!NtDisplayString | | | | 129 | 0xFFFFFFFF81A2117F | nt!NtDuplicateObject | | | | 130 | 0xFFFFFFFF81A18134 | nt!NtDuplicateToken | | | | 131 | 0xFFFFFFFF81AB14E8 | nt!NtEnumerateBootEntries | | | | 132 | 0xFFFFFFFF81AB278A | nt!NtEnumerateDriverEntries | | | | 133 | 0xFFFFFFFF91F04FFA | Gjglly | | | | 134 | 0xFFFFFFFF81AB10B7 | nt!NtEnumerateSystemEnvironmentValuesEx | | | | 135 | 0xFFFFFFFF81A9F073 | nt!NtEnumerateTransactionObject | | | | 136 | 0xFFFFFFFF91F051B6 | Gjglly | | | | 137 | 0xFFFFFFFF81A802D5 | nt!NtExtendSection | | | | 138 | 0xFFFFFFFF819A113A | nt!NtFilterToken | | | | 139 | 0xFFFFFFFF819B39FC | nt!NtFindAtom | | | | 140 | 0xFFFFFFFF819DCA86 | nt!NtFlushBuffersFile | | | | 141 | 0xFFFFFFFF819AD0F6 | nt!NtFlushInstructionCache | | | | 142 | 0xFFFFFFFF819781EB | nt!NtFlushKey | | | | 143 | 0xFFFFFFFF818B11C1 | nt!NtFlushProcessWriteBuffers | | | | 144 | 0xFFFFFFFF819C175B | nt!NtFlushVirtualMemory | | | | 145 | 0xFFFFFFFF81A82D64 | nt!NtFlushWriteBuffer | | Yes | We can see a module (Gjglly.sys), and nt!NtFlushWriteBuffer is hooked. Let's not jump to conclusions just yet as this could be a completely legitimate hook. First of all, what's Gjglly.sys? This is a driver in relation to AntiDebugLIB. An advanced software encryption tool. AntiDebugLIB is a useful tool that was designed in order to assist software developers protect their applications against advanced reverse engineering and software cracking. It offers a powerful advanced license control which allow developers to distribute trial versions of their applications securely. 2nd Method - Script The second method we will be using in this postmortem debugging example is an older script developed by Lionel d'Hauenens of Laboskopia. This script will only work with the x86 WinDbg client. Regardless, as we know, it's always best to debug a crash dump in the client based off of the system's architecture. Given the system that generated this crash dump was 32-bit, we'll be debugging it with the x86 WinDbg client. This script is incredibly helpful in not only checking the SSDT for hooking, but also detecting what is known as a Shadow SSDT hook. You can find a great article on Shadow SSDT hooking from my very good friend Harry - Shadow SSDT Hooking with Windbg. Nevertheless, if you don't understand French instructions, to install the script, simply drag and drop the script folder into your x86 Debuggers folder. Once it's installed, type the following command into WinDbg with your postmortem rootkit crash dump: kd> $$><script\@@init_cmd.wdbg So long as you installed the script properly, you should see the following: SysecLabs Windbg Script : Ok ('al' for display all commands) Once you see that which has verified the script is loaded properly, type the following command: !!display_system_call Here's a few excerpts: 007D 0003 OK nt!NtDeleteObjectAuditAlarm (81a46500) 007E 0002 HOOK-> *** ERROR: Module load completed but symbols could not be loaded for Gjglly.sys 007F 000A OK nt!NtDeviceIoControlFile (81a34f80) 0080 0001 OK nt!NtDisplayString (81949b44) 0081 0007 OK nt!NtDuplicateObject (81a2117f) 0082 0006 OK nt!NtDuplicateToken (81a18134) 0083 0002 OK nt!NtEnumerateBootEntries (81ab14e8) 0084 0002 OK nt!NtEnumerateDriverEntries (81ab278a) 0085 0006 HOOK-> Gjglly+0x1ffa (91f04ffa) 0086 0003 OK nt!NtEnumerateSystemEnvironmentValuesEx (81ab10b7) 0087 0005 OK nt!NtEnumerateTransactionObject (81a9f073) 0088 0006 HOOK-> Gjglly+0x21b6 (91f051b6) 00BC 0003 OK nt!NtOpenJobObject (81a912df) 00BD 0003 HOOK-> Gjglly+0x1f4c (91f04f4c) 00BE 0004 OK nt!NtOpenKeyTransacted (819727e1) 0143 0001 OK nt!NtSetUuidSeed (8195977b) 0144 0006 HOOK-> Gjglly+0x2372 (91f05372) 0145 0005 OK nt!NtSetVolumeInformationFile (81a6c5de) Here's Gjglly.sys again, and we can see it's hooking. At this point, we would be suspicious enough to run an ARK tool such as GMER. Of course, if we ran GMER at this point, it would show that the system is in fact infected with runtime2, and Gjglly.sys is our rootkit driver. Normally, by itself and by default, the runtime2 driver is runtime2.sys, not Gjglly.sys. In this specific scenario, niemiro used a different loader to inject the driver than the original, and renamed runtime2.sys to Gjglly.sys (a legitimate module name). Although GMER if run would still say the system is infected with a rootkit, and it would label Gjglly.sys as the rootkit driver, it's done not to trick various ARK tools, but the user. If you've ever been infected with runtime2, you know it additionally drops startdrv.exe in the Temp directory of the current Windows install. startdrv.exe is the part that infuriates those who become infected with runtime2, because it's the part that immediately makes you suspicious of an infection as it's a trojan dropper. This is the specific part of the rootkit that will cause slowness, garbage popups, etc. In this specific case, niemiro intentionally corrupted startdrv.exe which stopped it from executing entirely. You may be saying to yourself, what's the point of a rootkit's protection driver with no execution of payload, etc, by its dropped trojan? Well, there really is no point (unless your goal was to use something else that's malicious and not as obvious as a trojan dropper)! This was just an example to show how you can better hide a rootkit (protection driver, really) if you wanted to. Although ARK tools would still pick it up, it's not anywhere near as obvious to the user. Thanks for reading, and I will get around to doing a live debugging of runtime2 as soon as I can. -------------------- References Hunting rootkits with Windbg. Some notes about System Service Dispatch Table hook. Source
-
Today we're going to be taking a look into thermal zones, which are essentially different physical regions of the hardware platform that are partitioned. This act of partitioning is done so that when a sensor detects that a thermal zone is overheating, it will either use passive or active cooling to cool the devices in the specific thermal zone. I'm still learning about them in-depth as they're relatively confusing. ACPI thermal zone ACPI\ThermalZone\TZS0 has been enumerated. _PSV = 371K _TC1 = 0 _TC2 = 50 _TSP = 0ms _AC0 = 0K _AC1 = 0K _AC2 = 0K _AC3 = 0K _AC4 = 0K _AC5 = 0K _AC6 = 0K _AC7 = 0K _AC8 = 0K _AC9 = 0K _CRT = 373K _HOT = 0K _PSL - see event data. Having a look at the above event data, this is the thermal zone data for the TZS0 sensor. Without having other more detailed event data logs aside from this, I can only assume this is the sensor for the CPU. The reason for this is the _PSL child object is used to list the processors in the thermal zone. If we saw _TZD instead of _PSL, this would list the non-processor devices in the thermal zone. For the moment however, we'll just assume the entire system was overheating as this was a really hot laptop. Let's go down the line: PSV _PSV - Indicates the temperature at which the operating system started passive cooling control. In our case here, this was 371K (K = Kelvin). 371 Kelvin is 97.85 Celsius. The system we're dealing with in this post is an Acer Aspire 5740G, which according to tech specs houses an i5 430m for its processor. If we consult the manual: We can see the max temperature is 105C regarding the CPU core, and 100C for the integrated graphics + IMC. With this said, the CPU started throttling (passive countermeasure to overheating) at 97.85C. How did the CPU know when to start throttling? PROCHOT#! PROCHOT# is Intel's thermal throttle activity bit: Note it states - The TCC will remain active until the system deasserts PROCHOT#. In fancy software engineer talk, this simply means that so long as the temperatures continue to rise (or doesn't drop), it will continue to lower power consumption from the CPU until it's in a safe spot. The downside to this is in extreme situations of overheating (like this one here), we trip because we hung around at an unsafe operational temperature for too long (or got higher) and shut down to prevent permanent damage. TC1/2 _TC1/2 - These are both known as the Thermal Constants, which are essentially objects used to evaluate the constants _TC1/2 for use in the passive cooling formula. Performance [%]= _TC1 * ( Tn -Tn-1 ) + _TC2 * (Tn. - Tt) The return value is an integer containing Thermal Constant #'s 1 or 2. In our case, our return value was 50 for _TC2. TSP _TSP - Evaluates to a thermal sampling period (in tenths of seconds) used by Operating System-directed configuration and Power Management (OSPM) to implement the passive cooling equation. This value, along with _TC1 and _TC2, will enable OSPM to provide the proper hysteresis required by the system to accomplish an effective passive cooling. In our case, this was 0ms. AC(x) _AC(x) - This optional object, if present under a thermal zone, returns the temperature trip point at which Operating System-directed configuration and Power Management (OSPM) must start or stop active cooling, where (x) is a value between 0 and 9 that designates multiple active cooling levels of the thermal zone. In our case, we can see it does go 0-9, and all is listed as 0 Kelvin. CRT _CRT - Indicates the temperature at which the operating system will shut down as it simply cannot throttle (passive) or use fans (active) to succeed in cooling these temperatures in time before permanent damage. In this case, we can see it's 373k (373 Kelvin) when this occurred, which is 99.85 Celsius. Unsure as to why this is 99.85 and not 100 in our case, but I digress. Possibly it rounded up? HOT _HOT - Indicates the return value (temperature) at which Operating System-directed configuration and Power Management (OSPM) may choose to transition the system into the S4 sleeping state. -------------------- In any case, all we know is that this laptop was having some serious overheating problems. It was occurring mostly overnight when the system was being awoken from sleep to perform a defrag. The defrag was enough to push it to throttle/shutdown temperatures, which was also throwing bug checks as Windows wasn't happy it couldn't defrag. Thanks for reading, and hopefully more info on thermal zones in the near future. References ACPI-defined devices Advanced Configuration and Power Interface Specification Intel® Atom™ Processor 330 Series Datasheet Source
-
Stacks, stacks, and more stacks!
Aerosol posted a topic in Reverse engineering & exploit development
If you've ever debugged a crash dump before, user-mode or kernel, you've very likely seen a stack. If you debug crash dumps quite often, you've seen and traversed thousands of stacks, maybe more! For a long time I knew the basics behind a stack and what I was looking at/through for the most part, but really beyond that I didn't know much for quite awhile until I dug deep into dozens of documents and books as time went on. With that said, let's discuss stacks and their mechanics! The stack excerpt below is from an x86 0xF4 crash dump. The cause of the bug check and such is irrelevant, and this stack is purely for explanatory purposes. With that said, turn off your tingly BSOD senses for a moment and look at the functions and such for what they are, and not what they could have done to play a role in the crash : ) kd> k ChildEBP RetAddr a1e72ccc 81a8eec4 nt!KeBugCheckEx+0x1e a1e72cf0 81a1e85f nt!PspCatchCriticalBreak+0x73 a1e72d20 81a1e806 nt!PspTerminateAllThreads+0x2c a1e72d54 8185c986 nt!NtTerminateProcess+0x1c1 a1e72d54 77725d14 nt!KiSystemServicePostCall 0028f0d0 00000000 0x77725d14 k* will perform a stack unwind, or more specifically will display the stack backtrace. * denotes the placeholder for the various possible parameters that we can use, such as - kb, kv, kc, kd, the list goes on. Each of those all does something different, but for now we'll stick to plain old k for example purposes. Let's break this down one at a time! ChildEBP ChildEBP - First we have our ChildEBP, otherwise known as the 'base pointer', which is essentially nothing more than a pointer to a stack frame that has been set up by a piece of code (a reference to a stack of memory). As an example, let's take a look at the following command: dd a1e72cf0 l1 dd - This is a variation of plain old d, which simply means dump. If we however use dd, this will display/dump dword(s). a1e72cf0 - This is a pointer address from our stack, specifically from nt!PspCatchCriticalBreak+0x73. L1 - I've always been under the impression that this tells WinDbg to print a line based on what we're looking to do as far as the command goes. I've searched the WinDbg help doc far and wide for a conclusive answer, but I haven't found one yet. There are billions of people out there far smarter than I, and hopefully one of them reads my blog to tell me what it really does! EDIT: Hilariously enough, someone smarter than me did happen to come along. Thanks to Blair Foster, I now understand what L1 really does. its a size/range specifier. In the case of d* its used as size. So, dd L1 displays 1 dword, db L1 is 1 byte, etc. Thanks, Blair! If we go ahead and run this command, here's what we get: kd> dd a1e72cf0 l1 a1e72cf0 a1e72d20 Look familiar? a1e72d20 is another pointer address from our stack, but more specifically the pointer from the previous function in the stack - nt!PspTerminateAllThreads+0x2c. With this known, we can conclude that the ChildEBP also stores the previous function address. a1e72d20 81a1e806 nt!PspTerminateAllThreads+0x2c In this specific example, we don't have a good stack to show us what would happen if we went all the way back to what function spawned/began the stack. Taking a quick look through some x64 dumps (didn't have any good x86 ones), I dug up a quick stack. Try not to get overwhelmed with the differences between x86 and x64 as far as stack goes (even though there aren't really any). It's just more bits and bobs! 3: kd> k Child-SP RetAddr fffff880`033dfa58 fffff800`0302da3b nt!KeBugCheckEx fffff880`033dfa60 fffff800`031f0463 hal!HalBugCheckSystem+0x1e3 fffff880`033dfaa0 fffff800`0302d700 nt!WheaReportHwError+0x263 fffff880`033dfb00 fffff800`0302d052 hal!HalpMcaReportError+0x4c fffff880`033dfc50 fffff800`0302cf0d hal!HalpMceHandler+0x9e fffff880`033dfc90 fffff800`03020e88 hal!HalpMceHandlerWithRendezvous+0x55 fffff880`033dfcc0 fffff800`030d84ac hal!HalHandleMcheck+0x40 fffff880`033dfcf0 fffff800`030d8313 nt!KxMcheckAbort+0x6c fffff880`033dfe30 fffff800`030d07b8 nt!KiMcheckAbort+0x153 fffff880`09e9f638 00000000`00000000 nt!memcpy+0x208 Just by looking at the stack we can see it begins right at nt!memcpy+0x208, but let's show it the way we've been demonstrating: 3: kd> dd fffff880`033dfe30 l1 fffff880`033dfe30 00000000 We can see at address fffff880`033dfe30, the return value was zero. This tells us it wasn't called from another prior function, etc, and is the very beginning of the stack. Given the function itself is nt!memcpy, this is understandable. RetAddr RetAddr - Now that we understand our base pointer, we have our RetAddr, which implies return address. This is done because quite simply the CPU without being told what to do is pretty useless. We need to let it know what address to return to after it's done successfully executing the code, because all it's concerned about is instructions and executing their code. It has no idea how to handle them without this stuff set in place, or what to do after it's done. With that said, this is why we have our return address. If we take another look at our x64 stack excerpt: 3: kd> k Child-SP RetAddr fffff880`033dfa58 fffff800`0302da3b nt!KeBugCheckEx fffff880`033dfa60 fffff800`031f0463 hal!HalBugCheckSystem+0x1e3 fffff880`033dfaa0 fffff800`0302d700 nt!WheaReportHwError+0x263 fffff880`033dfb00 fffff800`0302d052 hal!HalpMcaReportError+0x4c fffff880`033dfc50 fffff800`0302cf0d hal!HalpMceHandler+0x9e fffff880`033dfc90 fffff800`03020e88 hal!HalpMceHandlerWithRendezvous+0x55 fffff880`033dfcc0 fffff800`030d84ac hal!HalHandleMcheck+0x40 fffff880`033dfcf0 fffff800`030d8313 nt!KxMcheckAbort+0x6c fffff880`033dfe30 fffff800`030d07b8 nt!KiMcheckAbort+0x153 fffff880`09e9f638 00000000`00000000 nt!memcpy+0x208 According to the stack, HalpMceHandlerWithRendezvous was called by HalHandleMcheck. We know that when the work HalpMceHandlerWithRendezvous was doing was finished, it would return back to HalHandleMcheck. We can confirm this by taking a look at the return memory addresses and using the ln command: 3: kd> ln fffff800`03020e88 (fffff800`03020e48) hal!HalHandleMcheck+0x40 ln - This command will display the function/routine at or near the given address. Bingo! Execution will resume afterwards in HalHandleMcheck, specifically 64 bytes from the start of the function. Functions/Call Site Functions/Call Site - Last but not least, we have our third column (it's not labeled above in any of the stack excerpts). Interestingly enough, x64 stacks do label their function columns, specifically as Call Site. In the above stack x64 excerpts however, I removed them to avoid confusion! : ) Here is what a non-edited x64 stack looks like: 3: kd> k Child-SP RetAddr Call Site fffff880`033dfa58 fffff800`0302da3b nt!KeBugCheckEx fffff880`033dfa60 fffff800`031f0463 hal!HalBugCheckSystem+0x1e3 fffff880`033dfaa0 fffff800`0302d700 nt!WheaReportHwError+0x263 fffff880`033dfb00 fffff800`0302d052 hal!HalpMcaReportError+0x4c fffff880`033dfc50 fffff800`0302cf0d hal!HalpMceHandler+0x9e fffff880`033dfc90 fffff800`03020e88 hal!HalpMceHandlerWithRendezvous+0x55 fffff880`033dfcc0 fffff800`030d84ac hal!HalHandleMcheck+0x40 fffff880`033dfcf0 fffff800`030d8313 nt!KxMcheckAbort+0x6c fffff880`033dfe30 fffff800`030d07b8 nt!KiMcheckAbort+0x153 fffff880`09e9f638 00000000`00000000 nt!memcpy+0x208 As we can see, there's Call Site! In x86 crash dumps however, it's not labeled. I don't need to paste the stack excerpt we used from above as I didn't edit it, so you can just scroll back up and take a quick look. It should be no mystery that this third and final column displays the function (and routine) names throughout the stack. Do note that they are in direct correlation with the current loaded symbols. If you don't have proper symbols, you're going to get an unresolved function (or routine), and it's going to look like junk. -------------------- Thanks for reading! In my next post I plan on going into the x86 registers (maybe x64 although it'll be a lot of work -- may save that for a future post). Source-
- 1
-
As I discussed towards the end of my last post regarding stacks, my next post was likely going to be about registers. Well, here we are! I had originally planned on discussing both x86 and x64 registers in a single post, but this posed two main problems. The first problem was this would have been a very long post! The second problem, which is a considerably larger one, is I don't know x64 assembly/architecture as much as I'd like to feel confident in making a post about it. The good news is whenever I am brushed up enough in regards to x64's architecture to write a detailed post, I can simply jump right in as I did all the dirty work right here in this post! Happy days. Memory Hierarchy First off, it's important to discuss and understand what a register is. Before we get into that however, let's have a look at my favorite image of the memory hierarchy: It's safe to say there are probably thousands of images regarding the memory hierarchy throughout CS books, documents, and presentations, but this one takes the cake for me! It's about as good as it visually gets for a hierarchy image, and although it doesn't display a few key points, I can do that myself right here in this post. What are the key points I'm talking about that are missing from this image? Well, from the bottom>top, we're going from slowest to fastest. If we're coming from the top>bottom, we're going from the fastest to the slowest (in regards to read and write access time). It's absolutely imperative to also understand that the faster we get, the more expensive we get, and the slower we get, the less expensive we get (in regards to USD). With that now known, you can imagine that the read/write from a removal media device (such as USB) is slower than the read/write from your hard drive, but is less expensive. As this is a post strictly about registers, I won't go into the complexities and intricacies of each part of the hierarchy, and will instead focus on the registers themselves. As far as access time goes, let's compare registers and the hard drive as an example: Registers - 1-2ns (nanoseconds) Hard Drive - 5-20ms (milliseconds) -- It's all dependent on the architecture of the processor, really. These are rough #'s. Cue the amazing Grace Hopper! Why are registers so fast? Registers are actually circuits which are built/wired (literally) into the Arithmetic logic unit (ALU), which is also widely considered the fundamental building block of a CPU. With that said, we really can't get any closer, which means there's also no data transfer overhead as there are barely any clock cycles required. Also, a CPU's instruction set tends to work with registers more than it does with actual memory locations. Speaking of clock cycles, here's a chart displaying the cycles regarding the memory hierarchy: As we can see, a register only takes one clock cycle. What is a register? Now that we understand the basic fundamentals behind the memory hierarchy and where the register resides on the hierarchy, we can discuss what a register actually is! In its most basic definition, a register is used to store small pieces of data that the processor is actively working on. There are many different registers and categories of registers, all of which essentially do something different, however you can generally break registers down into two types. For example, regarding the first type, we have the General purpose register (GPR), which essentially stores data and performs arithmetic based on an instruction (addition, subtraction, multiplication, etc). Once the arithmetic is finished (or the manipulation of data/memory is finished), it's entirely up to what the instruction is set to do. It can either store it back into memory with the same instruction, a different one, etc. Regarding the second type, we have the Special purpose register (SPR) which as the name implies has a special meaning and specific purpose. For example, the SP (Stack Pointer) register is a SPR in addition to being a GPR regarding the IA-32 architecture. This register is used to have the CPU store the address of the last program request in a stack. Among other things, as new requests are coming in, they push down the older ones in the stack, with the most recent request always residing at the top of the stack. It's important to note that at every clock tick, there are specific values regarding registers. The values stored in a specific register may have been updated on a tick, so the values may not be the same as they were prior to the tick. For example, when an interrupt fires, register values are copied to a stack and stay on that stack while an Interrupt Service Routine (ISR) is being executed by the CPU. Once the interrupt is properly handled, the original register values are loaded back from the stack so they can continue to service the instruction they were previously working with. What I described above is known as context switching, which is essentially the jump of instructions from CPU > ISR. Although unrelated yet interesting to note, in some special cases regarding 0x101 bug checks depending on what actually caused the bug check, you may need to have knowledge of context switching to properly debug. With all of the above said, there's about a dozen different ways I could go at this point. I could go on to talk about the register file, the many different and various categories of registers, etc. However, let's jump ahead to register renaming as that's a pretty important topic. Register Renaming Register renaming is essentially a form of pipelining that deals with data dependencies between instructions by renaming their register operands. The way renaming works is, it will go ahead and replace the architectural register (user-accessible registers, or more easily just known to us as 'the registers') names (value names) with a new value name for each instruction destination operand. Thanks to register renaming, we can also successfully perform what is known as Out-of-order execution (OOE). How exactly does it allow OOE to be performed? Register renaming entirely eliminates name dependencies between instructions, and recognizes true dependencies. True dependencies occur when an instruction depends on the result of a subsequent instruction. Given the above is now explained, here's a good time to explain data hazards. Data hazards occur when instructions that exhibit data dependence modify data in different stages of a pipeline. Ignoring a data hazard can lead to what is known as a race condition, which is when the order of the data that was outputted was not the intended order. We have three main data hazards: Read-after-write (RAW), also known as a true dependency. Write-after-read (WAR), also known as an anti-dependency. Write-after-write (WAW), also known as an output dependency. 1. What is RAW? Let's take two instruction locations (l1, l2). A prime RAW example is when l2 tries to read a source before l1 writes to it. l2 is attempting to refer to a result that hasn't been calculated or retrieved yet by l1. 2. What is WAR? Let's once again take l1 & l2. l2 tries to write a destination before it is read by l1. This is a problem in concurrent execution, which notes of course they must work concurrently and not sequentially. If they do work sequentially, then we have a data hazard like so. 3. What is WAW? Taking l1 & l2 one last time, l2 tries to write an operand before it is written by l1. With register renaming, since we're ultimately maintaining a status bit for each value that indicates whether or not it has been completed, it allows the execution of two instruction operations to be performed out of order when there are no true data dependencies between them. This removes WAR/WAW, and of course leaves RAW intact as discussed above. x86 Registers In WinDbg, by using the r command we can go ahead and dump the registers from the context of the thread that caused the crash. For example: kd> r eax=818f4920 ebx=86664d90 ecx=818fb9c0 edx=000002d0 esi=818f493c edi=00000000 eip=818c07dd esp=a1e72cb0 ebp=a1e72ccc iopl=0 nv up ei pl nz na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000206 x86 (IA-32) has eight GPRs, which are: EAX EBX ECX EDX ESI EDI EBP ESP Great, so there's our eight GPRs. Now we can go ahead and break them down: EAX - The 'A' in the EAX register implies it's the accumulator register for operands and results data. EBX - The 'B' in the EBX register implies it's the pointer to the data in the DS segment. DS is the current data segment. It also means 'base register'. ECX - The 'C' in the ECX register implies it's the counter for storing loop and string operations. EDX - The 'D' in the EDX register implies it's the I/O pointer. ESI - The 'SI' in the ESI register implies it's the Source Index, which is a pointer to data in the segment pointed to by the DS register. EDI - The 'DI' in the EDI register implies it's the Destination Index, which is a pointer to data (or a destination) in the segment pointed to by the ES register. It's essentially the counterpart to the ESI register, for lack of a better word. EBP - The 'BP' in the EBP register implies it's the Base Pointer, which is the pointer to data on the stack. ESP - The 'SP' in the ESP register implies it's the Stack Pointer, which is used to detect the location of the last item put on the stack. Whew, alright! So there's just a few things I'd like to quickly explain as well as we haven't covered all of the bases: EAX - The 'AX' in the EAX register is used to address only the lower 16 bits of the register. If we were to reference all 32 bits, we'd use all of EAX, and not just AX. EIP - I didn't forget this guy, don't worry! The 'IP' in the EIP register implies it's the Instruction Pointer, which can also actually be called the 'program counter'. It contains the offset in the current code segment for the next instruction that will be executed. It's also interesting to note that EIP cannot be accessed by software, and is explicitly controlled by control-transfer instructions such as JMP, CALL, JC, and RET. Aside from control-transfer instructions, interrupts and exceptions can also access EIP directly. Okay, so I can't mention control-transfer instructions and then not explain them. I mean, I could... but I wouldn't be happy. Control-transfer instructions specifically control the flow of program execution. There are quite a few control-transfer instructions, but I will discuss the ones I mentioned that can directly access EIP: JMP - Jump. JMP transfers program control to a different point in the instruction stream without recording any return information. The destination operand specifies the address of the instruction being jumped to. This operand can be an immediate value, a GPR, or a memory location. The JMP instruction can be used to actually execute four different types of jumps: 1. Near jump - A jump to an instruction within the segment currently pointed to by the CS register. It can also at times be referred to as an intrasegment jump. 2. Short jump - A type of near jump in that the jump range is limited to -128 to +127 from the current EIP value. 3. Far jump - A jump to an instruction that's located in a different segment than the current code segment, but at the same privilege level. It can also at times be referred to as an intersegment jump. 4. Task switch - A jump to an instruction that's located in a different task. Note that a task switch can only be accomplished in protected-mode, which not to fly too off the handle here, but it's necessary to explain. Rather than explaining it here though as it's a bit large, I'll explain it below in a short while. CALL - Call procedure. CALL pushes the current code location onto the hardware supported stack in memory, and then performs an unconditional jump to the code location indicated by the label operand. Unlike the simple jump instructions I listed above, the call instruction saves the location to return to when the subroutine completes. JC - Jump if carry flag is set. Ret - Return. This instruction transfers control to the return address located on the stack, which is usually placed on the stack by a call instruction that we discussed above. It then performs an unconditional jump to the retrieved code location. For example: call <label> ret I mentioned intersegment/intrasegment jumps above. Intersegment jumps can transfer control to a statement in a different code segment, while intrasegment jumps are always between statements in the same code segment. Now that we have the above control-transfer instructions explained, let's discuss protected-mode as I mentioned above. Before further discussing protected-mode and the similarly named but very different real-mode, we'll need to do a bit of a history lesson. Way before my time, back in the late 70's (76-78), Intel's 16-bit 8086 processor was released. It was 16-bit because its internal registers + internal/external data buses were 16 bits wide. A 20-bit external address bus meant this beast could address a whopping 1 MB's of memory! 1 MB may not seem like anything these days, but it was actually considered more than overkill around this time. Due to this being the case, the max linear address space was limited to a mere 64 KB. Aside from 1 MB being overkill, this was also because the internal registers were only 16 bits wide. There were two problems here: 1. Programming over 64 KB boundaries meant adjusting segment registers. 2. As time went on, applications were being released that made this mere 64 KB seem like the measly number it is today. What was the saving grace? Intel's 80286 processor was released in 1982! Well, what's so great about this processor that solve the above two problems? The 80286 processor had two operating modes, as opposed to the 8086 which only had one. The operating modes were: 1. Real-Mode (backwards compatible 8086 mode). 2. Protected-Mode. The 80286 processor had a 24-bit address bus, which could address up to 16 MB! That's 15 more MB than its predecessor. There's too much good stuff here, so let's discuss the problems. The problems were certainly problems, and they were considerably big ones: - DOS apps couldn't easily be ported to protected-mode granted that most/if not all DOS apps were developed in a way that made them incompatible. - The 80286 processor couldn't successfully revert back to the backwards compatible real-mode without a CPU reset. Later on however in 1984, IBM added circuitry that allowed a special series of instructions to successfully cause a revert without initiating a CPU reset. This method while certainly being a great feat, posed quite the performance penalty. Later on it was discovered that initiating a triple fault was a much faster and cleaner way, but there was still yet to be a 'painless' method of transition. With the above said, the successor was released which is the 80386. The 80386 had a 32-bit address bus, which allowed for 4 GB of memory access. 1 MB > 16 MB > 4 GB, quite the increase! In addition, the segment size was increased to 32-bits, which meant there wasn't a need to switch between multiple segments to access the full address space of 4 GB. Whew! With all of this known, what is protected-mode actually so great for at this point? Protected-mode allows for virtual memory, paging, ability to finally painlessly switch back to real-mode without a CPU reset, etc. How do we actually get into protected-mode? The Global Descriptor Table (GDT) needs to be created with a minimum of three entries. These three entries are a null descriptor, a code segment descriptor, and a data segment descriptor. Afterwards, the PE bit needs to be set in the CR0 register and a far JMP needs to be made to clear the prefect input queue (PIQ). // Set PE bit mov eax, cr0 or eax, 1 mov cr0, eax // Far JMP (Remember CS = Code Segment) jmp cs:@pm @pm: // Now in protected-mode So we got to most of the registers from the x86 register dump excerpt, but we're missing these ones: nv up ei pl nz na pe nc These are the current contents of the FLAGS register (there are 20[?] different flags), which is the status register for x86. nv - No overflow. up - Up. ei - Enable interrupt. pl - Plus (I believe). nz - Not zero. na - Not auxiliary carry. pe - Parity even. nc - No carry. Disassembly Example Let's now dump a stack from a random x86 crash dump to show an example of some of the registers we talked about, some assembly code, and instructions: ChildEBP RetAddr a1e72ccc 81a8eec4 nt!KeBugCheckEx+0x1e a1e72cf0 81a1e85f nt!PspCatchCriticalBreak+0x73 a1e72d20 81a1e806 nt!PspTerminateAllThreads+0x2c a1e72d54 8185c986 nt!NtTerminateProcess+0x1c1 a1e72d54 77725d14 nt!KiSystemServicePostCall 0028f0d0 00000000 0x77725d14 Let's go ahead and disassemble the nt!PspTerminateAllThreads+0x2c kernel function: nt!PspTerminateAllThreads+0x2c: 81a1e85f 8b450c mov eax,dword ptr [ebp+0Ch] // Move value stored at memory address in the ebp+0Ch register to the eax register. 81a1e862 8b4048 mov eax,dword ptr [eax+48h] // Move value stored at memory address in the eax+48h register to the eax register. 81a1e865 8945f0 mov dword ptr [ebp-10h],eax // Move contents of eax register to the ebp-10h register. 81a1e868 6a00 push 0 // Push a 32-bit zero on the stack. 81a1e86a 8bc7 mov eax,edi // Move contents of the edi register into the eax register. 81a1e86c c745fc22010000 mov dword ptr [ebp-4],122h // Store the 32-bit value 122h to the ebp-4 register. 81a1e873 e8bf010000 call nt!PspGetPreviousProcessThread (81a1ea37) // Call function name nt!PspGetPreviousProcessThread. 81a1e878 8b5d14 mov ebx,dword ptr [ebp+14h] // Moving value stored at memory address in the ebp+14h register to the ebx register. Hope you enjoyed reading! References Intel 80386 Reference Programmer's Manual X86 Assembly/High-Level Languages A Guide to Programming Intel IA32 PC Architecture Segment Registers: Real mode vs. Protected mode Source
-
Here we are, part two! I thought rather than doing a live debugging of runtime2 as I discussed in my last rootkit debugging post, I'd debug a different rootkit. I chose Rustock.B (PE386) as it's a pretty notorious rootkit, and in my opinion is a lot of fun to debug. It's always a great learning experience to debug, reverse, and research things for yourself as well. I have a map of rootkits I want to debug and reverse as the weeks go by, so expect many more of these. Let's get started! First off, before we get into the fun debugging/reversal, what do we know about Rustock? We know a lot! It's a fairly dated rootkit, and has been reversed time and time again by researchers, etc. It's a great example to use when showing some of the neat things a rootkit can do. It was originally developed to distribute spam email, which was way back in the day. It was first discovered in 2006, and began to increase by a significant number in 2008. By mid 2010, it was one of the most known rootkit related threats (and arguably malware in general). (thanks to MSIR for the image!) Rustock has three encrypted components which we will discuss below, one at a time: Dropper Component The dropper is the bad guy, the guy nobody likes. Malware droppers have one primary job, and it's once they are executed, install the specified malware. Malware writers can have their droppers do other things however, which Rustock's of course does. They are called droppers because they essentially 'drop' the malware onto the target system. Rustock's dropper runs specifically in user-mode, and decrypts/drops the rootkit component driver (our 3rd component that we will discuss later on). Interestingly enough, during the rootkit's time period of prevalence, the dropper also went ahead and contacted a Command and Control (C&C) Server to check for updates. C&C's have different structures, all of which are different. In most cases however, especially in its most basic definition, C&C's are used to send commands and receive outputs of machines part of a botnet. (thanks again to MSIR for the image!) In addition to contacting a C&C server, the dropper component also checks the registry to ensure that a previous Rustock infection hasn't already taken place so reinfection (which could cause obvious problems) doesn't happen. It checks the registry as there are keys which are installed when an infection takes place, such as PE386 (the key used to survive a reboot among other things). Driver Installer Component Our second component is the driver installer, which runs in kernel-mode as a disguised Windows system driver (textbook rootkit behavior). It historically replaces drivers such as beep.sys as well as null.sys with a copy, and then afterwards replaces it once started. If however this replacement method is unsuccessful, it falls back to a method I've seen occur much more, which the dropper will instead use a randomly-generated or hard-coded filename for the driver. Two hard-coded filenames have been glaide32.sys and lzx32.sys, with the latter being the most popular. As far as randomly-generated filenames go, 7005d59.sys was the most typical. Older versions of the rootkit would install themselves to null shares to hide in a system driver, and then proceed to drop the installer as an alternate data stream (ADS) (%Windir%\System32:lzx32.sys, for example). Modern versions of the rootkit however use system service hooking. Rootkit Driver Component Our third and final component is the rootkit driver, which runs in kernel-mode like the driver installer. As we discussed above regarding our first component, this component is decrypted by the dropper which then allows the rootit driver to inject a copy of its decrypted code into itself before transferring control over to the newly instantiated copy. The decryption process is accomplished inside a buffer allocated in kernel memory by using ExAllocatePool. It specifically contains the code managing the backdoor functionality, such as the actual ability to contact the C&C server discussed above, and executing instructions sent by Rustock operators. The kernel-mode side of the rootkit communicates with its user-mode bot component (C&C, etc) using INT 2Eh interrupts for NT/2k (a bit different for XP), which will be shown in action coming up. Aside from communication, the rootkit component hid itself by hooking different SSDT functions such as: ZwQuerySystemInformation ZwCreateKey ZwOpenKey ...will discuss late It hid its network/disk operations by hooking ntoskrnl.dll and ntdll.dll functions, as well as various network drivers such as: tcpip.sys wanarp.sys ndis.sys It hooked the following network drivers to bypass firewalls and manipulate packets. In addition to the INT 2Eh interrupts being shown in action, I'll also be showing all of the various hooking, etc. Now that we've gotten some of the history and information out of the way, let's start with the debugging and reversal of the rootkit. Rootkit Debugging/Reversal I had to go through a few hoops to create an environment in which Rustock.B could be properly examined. It wasn't unfortunately as simple as executing it on an XP VM, although it wasn't excruciatingly painful to set up either. Also, for any amateur malware analysts who get curious (like me) and try to execute Rustock on Windows 7 x86 to see what will happen, it throws an access violation : ) Nothing too cool, unfortunately! I have however read reports saying it runs on the beta of Vista. After I had the basics done (isolated from host network, etc), I had to make three changes to get the rootkit to properly execute on an XP SP2 guest: 1. Disable both Physical Address Extension (PAE) and Data Execution Prevention (DEP). This is easily done by modifying the boot.ini to look like the following: [boot loader] timeout=30 default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS [operating systems] multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft XP Home Edition" /execute /fastdetect multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft XP Home Edition, 1 core" /execute /fastdetect /NUMPROC=1 multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft XP Home Edition, 4 cores" /execute /fastdetect /NUMPROC=4 /execute parameter is another way of saying /noexecute=alwaysoff, which disables DEP and PAE. /fastdetect parameter disables detection on all serial and parallel ports. It's not necessary in this case by any means, but it does allow for a slightly faster boot time. It's just a habit from the XP days : ) /NUMPROC=1 and NUMPROC=4 are almost self-explanatory, really. This parameter limits the OS when it boots to either 1 core or 4 cores. In our case, Rustock (afaik) cannot execute on anything more than 2 cores, so I went with 1 for safety (thanks EP_X0FF). Here's what it looks like at the boot selection screen: 2. Uninstall VMware Tools, restart. 3 (optional). Insert the following into the VM config file: isolation.tools.setPtrLocation.disable = "TRUE" isolation.tools.setVersion.disable = "TRUE" isolation.tools.getVersion.disable = "TRUE" // Thwarts backdoor I/O checks. monitor_control.disable_directexec = "TRUE" // Thwarts descriptor table registers checks. VMware interprets each assembly instruction instead of the processor executing them. monitor_control.disable_chksimd = "TRUE" monitor_control.disable_ntreloc = "TRUE" monitor_control.disable_selfmod = "TRUE" monitor_control.disable_reloc = "TRUE" monitor_control.disable_btinout = "TRUE" monitor_control.disable_btmemspace = "TRUE" monitor_control.disable_btpriv = "TRUE" monitor_control.disable_btseg = "TRUE" After the above, Rustock executes as expected with no problems. One of the first few things Rustock does as discussed above is create a registry subkey associated with a hidden service known as pe386. By using SwishDbgExt as we've used many times before in my blog posts, we can dump the list of services on the system using the !ms_services command: lkd> !ms_services Implicit process is now 821ae9a0 Loading User Symbols [209] | 0x01 | | pe386| Win23 lzx files loader | SERVICE_RUNNING | \Driver\pe386 As we can see, this successfully shows us our hidden service, and notes it is in fact running. With this said, we can confirm infection was a success. As we discussed above, older versions of Rustock use alternate data streams (ADS). It goes one step further and prevents access from NTFS.sys (NT File System driver) or FASTFAT.sys (FAT File System driver), therefore they cannot directly communicate with the files in the data stream. It does this by hooking various file system related IRP functions that control create/delete operations regarding the ADS stream. Rustock often hooks IoCallDriver, which sends an IRP to certain drivers. We can the act of filtering in action here: lkd> u poi(poi(iofcalldriver+2)) f6fb9dae 56 push esi f6fb9daf 57 push edi f6fb9db0 8bf9 mov edi,ecx f6fb9db2 8b7708 mov esi,dword ptr [edi+8] f6fb9db5 3b352ceefbf6 cmp esi,dword ptr ds:[0F6FBEE2Ch] f6fb9dbb 7509 jne f6fb9dc6 f6fb9dbd 52 push edx f6fb9dbe 57 push edi The poi operator is used so when the parameter contains IofCallDriver, WinDbg will break at the specified address. lkd> !address f6fb9dae address f6fb9dae not found in any known Kernel Address Range ---- The !address command is used afterwards on the SP to show memory region usage and attributes. Rustock hooks IA32_SYSENTER_EIP (0x176) for XP (remember, INT 2Eh interrupts for NT/2k), which is the kernel's EIP for SYSENTER. SYSENTER is an Intel instruction which enables fast entry to the kernel, avoiding interrupt overhead. AMD's version is known as SYSCALL, which overall does the same thing, although operates a bit differently. In any case, as I discussed earlier in the post, this is what Rustock uses to communicate between user-mode and kernel-mode. It's also ultimately hooked to execute code every time a system call is made. As we have a modified SYSENTER handler, this is where SSDT functions labeled above come into play. This was done to intercept system calls on a thread-level basis rather than using KeServiceDescriptorTable to hook on a global basis. 1. ZwOpenKey's API was modified so that whenever anything but services.exe tried to obtain a handle, it'd return STATUS_OBJECT_NAME_NOT_FOUND. This was done to prevent unauthorized access to the pe386 key. 2. ZwCreateKey's API was modified similarly to that of OpenKey, which is when any other process other than services.exe tries to create a key named pe386, CreateKey returns the same error as OpenKey. 3. ZwQuerySystemInformation's API was modified to zero out the usage time in kernel and user mode for services.exe, and adds it to the first process in the processes list (sysidle process). This was primarily done to counteract if a user were to check services.exe with Process Explorer, as it would raise red flags. We can check for the 0x176 hook manually and automatically using a script. Let's first view the manual way: lkd> rdmsr 0x176 msr[176] = 00000000`806ccc3d The rdmsr command is used to view the state of a model-specific register (MSR). lkd> !address 806ccc3d 804d7000 - 00215000 Usage KernelSpaceUsageImage ImageName ntoskrnl.exe Using our familiar !address command, we can see that to avoid easy hook detection, Rustock has the EIP address point to the same module as KiFastCallEntry (ntoskrnl.exe, or another variation of the NT Kernel). I've seen ntkrnlpa.exe as well. lkd> dc 806ccc3d 806ccc3d 8ee6c2e9 4c444e76 485f4445 5f445241 ....vNDLED_HARD_ 806ccc4d 4f525245 000a0d52 1c000000 4e000000 ERROR..........N 806ccc5d 41505f4f 5f534547 49415641 4c42414c O_PAGES_AVAILABL 806ccc6d 000a0d45 18000000 50000000 4c5f4e46 E..........PFN_L 806ccc7d 5f545349 52524f43 0d545055 1c00000a IST_CORRUPT..... 806ccc8d 4e000000 5f534944 45544e49 4c414e52 ...NDIS_INTERNAL 806ccc9d 5252455f 0a0d524f 24000000 50000000 _ERROR.....$...P 806cccad 5f454741 4c554146 4e495f54 4e4f4e5f AGE_FAULT_IN_NON dc is actually a parameter to show ASCII characters and dwords. d* on its own simply means 'display memory'. I've discussed this command in a previous blog post, but I believe it was dd that I used in that scenario. dd is the same as dc, except it doesn't display ASCII characters. By using this command on the 0x176 MSR address, this is where we can see Rustock replaced the FATAL_UNHANDLED_HARD_ERROR string with malicious code that's ultimately used to execute various functions of the rootkit. Hilariously enough, the original meaning of this string is a bug check code (0x4C). We can see where it performs a jump to its malicious code by further disassembling the MSR address. Unfortunately I forgot to bring the .txt file containing the WinDbg code, so I loaded up a snapshot and did the disassembly real quick to show in an image: Now that we've seen how to manually view the 0x176 hook manually, let's view it automatically using another tool we've used before, the SysecLabs script: lkd> !!display_current_msrs ################################### # Model-Specific Registers (MSRs) # ################################### Processor 00 IA32_P5_MC_ADDR msr[00000000] = 0 IA32_P5_MC_TYPE msr[00000001] = 0 IA32_MONITOR_FILTER_LINE_SIZE msr[00000006] = 0 IA32_TIME_STAMP_COUNTER *msr[00000010] = 000006ea`1ef96bef IA32_PLATFORM_ID msr[00000017] = 0 IA32_APIC_BASE *msr[0000001B] = 00000000`fee00900 MSR_EBC_HARD_POWERON msr[0000002A] = 0 MSR_EBC_SOFT_POWERON msr[0000002B] = 0 MSR_EBC_FREQUENCY_ID msr[0000002C] = 0 IA32_BIOS_UPDT_TRIG msr[00000079] = 0 IA32_BIOS_SIGN_ID *msr[0000008B] = 00000028`00000000 IA32_MTRRCAP *msr[000000FE] = 00000000`00000508 IA32_SYSENTER_CS *msr[00000174] = 00000000`00000008 IA32_SYSENTER_ESP *msr[00000175] = 00000000`f8974000 IA32_SYSENTER_EIP *msr[00000176] = -># HOOK #<- 00000000`806ccc3d nt!_NULL_IMPORT_DESCRIPTOR <PERF> (nt+0x1f5c3d) (806ccc3d) => Original : nt!KiFastCallEntry (804def6f) In addition to hooking SYSENTER, it also hooks the Interrupt Descriptor Table (IDT). The IDT is used to properly respond to interrupts and exceptions. We can view the IDT with SwishDbgExt: lkd> !ms_idt |-----|-----|--------------------|--------------------------------------------------------|---------|--------| | Cre | Idx | Address | Name | Patched | Hooked | |-----|-----|--------------------|--------------------------------------------------------|---------|--------| | 0 | 0 | 0xFFFFFFFF804DFBFF | nt!KiTrap00 | | No | | 0 | 1 | 0xFFFFFFFF804DFD7C | nt!KiTrap01 | | No | | 0 | 2 | 0x000000000000112E | *UNKNOWN* | | No | | 0 | 3 | 0xFFFFFFFF804E015B | nt!KiTrap03 | | No | | 0 | 4 | 0xFFFFFFFF804E02E0 | nt!KiTrap04 | | No | | 0 | 5 | 0xFFFFFFFF804E0441 | nt!KiTrap05 | | No | | 0 | 6 | 0xFFFFFFFF804E05BF | nt!KiTrap06 | | No | | 0 | 7 | 0xFFFFFFFF804E0C33 | nt!KiTrap07 | | No | | 0 | 8 | 0x0000000000001188 | *UNKNOWN* | | No | | 0 | 9 | 0xFFFFFFFF804E1060 | nt!KiTrap09 | | No | | 0 | 10 | 0xFFFFFFFF804E1185 | nt!KiTrap0A | | No | | 0 | 11 | 0xFFFFFFFF804E12CA | nt!KiTrap0B | | No | | 0 | 12 | 0xFFFFFFFF804E1530 | nt!KiTrap0C | | No | | 0 | 13 | 0xFFFFFFFF804E1827 | nt!KiTrap0D | | No | | 0 | 14 | 0xFFFFFFFF804E1F25 | nt!KiTrap0E | | No | | 0 | 15 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 16 | 0xFFFFFFFF804E237F | nt!KiTrap10 | | No | | 0 | 17 | 0xFFFFFFFF804E24BD | nt!KiTrap11 | | No | | 0 | 18 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 19 | 0xFFFFFFFF804E262B | nt!KiTrap13 | | No | | 0 | 20 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 21 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 22 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 23 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 24 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 25 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 26 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 27 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 28 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 29 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 30 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 31 | 0xFFFFFFFF806EDFD0 | *UNKNOWN* | | No | | 0 | 42 | 0xFFFFFFFF804DF417 | nt!KiGetTickCount | | No | | 0 | 43 | 0xFFFFFFFF804DF522 | nt!KiCallbackReturn | | No | | 0 | 44 | 0xFFFFFFFF804DF6C7 | nt!KiSetLowWaitHighThread | | No | | 0 | 45 | 0xFFFFFFFF804E0032 | nt!KiDebugService | | No | | 0 | 46 | 0xFFFFFFFF806CCC38 | nt!_NULL_IMPORT_DESCRIPTOR (nt+0x1f5c38) | | Yes | As mentioned earlier above, Rustock also hooks INT 2Eh to communicate between its user and kernel mode components. This is done specifically for older systems/hardware that don't support SYSENTER fastcalls, as KiSystemService is a user mode functions dispatcher and handler. We can see the hook here: lkd> !idt 2e Dumping IDT: 2e: 806ccc38 nt!_NULL_IMPORT_DESCRIPTOR <PERF> (nt+0x1f5c38) On a healthy x86 system, if you go ahead and dump the IDT, the only thing that should show is nt!KiSystemService. For example: kd> !idt 2e Dumping IDT: 823f7400 18b78dea0000002e: 8185c77e nt!KiSystemService Removal These days, the removal of Rustock is extremely trivial. When I ran GMER, Rustock would cause it to hang inevitably. I imagined this would occur, even with the random .exe name. However, I tried something strange out of curiosity and it ended up working, which was to run as owner. Before it successfully scanned however without hanging interruptions, here's what it displayed: After pressing 'OK' for both, GMER successfully scanned. Here were the results: We can see GMER detected the rootkit without too much issue, and we can also see our best friend pe386. Removal was pretty painless, all I had to do was kill and delete the service by right-clicking it within GMER, and also ridding of the process, library, and module. After a restart was completed, performing a live debugging showed completely opposite (and normal) results. I will show them below, one at a time. PE386 IofCallDriver Hook lkd> u poi(poi(iofcalldriver+2)) nt!IopfCallDriver: 804e3d50 fe4a23 dec byte ptr [edx+23h] 804e3d53 8a4223 mov al,byte ptr [edx+23h] 804e3d56 84c0 test al,al 804e3d58 0f8e8b860300 jle nt!IopfCallDriver+0xa (8051c3e9) 804e3d5e 8b4260 mov eax,dword ptr [edx+60h] 804e3d61 83e824 sub eax,24h 804e3d64 56 push esi 804e3d65 894260 mov dword ptr [edx+60h],eax lkd> !address 804e3d50 804d7000 - 00215000 Usage KernelSpaceUsageImage ImageName ntoskrnl.exe SYSENTER Hook - Manual lkd> rdmsr 0x176 msr[176] = 00000000`804def6f lkd> dc 804def6f 804def6f 000023b9 0f306a00 8ed98ea1 400d8bc1 .#...j0........@ 804def7f 8bffdff0 236a0461 026a9c52 9d08c283 ....a.j#R.j..... 804def8f 01244c80 ff1b6a02 df030435 55006aff .L$..j..5....j.U 804def9f 8b575653 dff01c1d 8b3b6aff 000124b3 SVW......j;..$.. 804defaf c733ff00 ffffff03 186e8bff ec83016a ..3.......n.j... 804defbf 9ced8148 c6000002 00014086 ec3b0100 H....... @....;. 804defcf ff6e850f 6583ffff 46f6002c ae89ff2c ..n....e,..F,... 804defdf 00000134 fe37850f 5d8bffff 687d8b60 4.....7....]`.}h SYSENTER Hook - Script lkd> !!display_current_msrs ################################### # Model-Specific Registers (MSRs) # ################################### Processor 00 IA32_P5_MC_ADDR msr[00000000] = 0 IA32_P5_MC_TYPE msr[00000001] = 0 IA32_MONITOR_FILTER_LINE_SIZE msr[00000006] = 0 IA32_TIME_STAMP_COUNTER *msr[00000010] = 0000007f`ec25230f IA32_PLATFORM_ID msr[00000017] = 0 IA32_APIC_BASE *msr[0000001B] = 00000000`fee00900 MSR_EBC_HARD_POWERON msr[0000002A] = 0 MSR_EBC_SOFT_POWERON msr[0000002B] = 0 MSR_EBC_FREQUENCY_ID msr[0000002C] = 0 IA32_BIOS_UPDT_TRIG msr[00000079] = 0 IA32_BIOS_SIGN_ID *msr[0000008B] = 00000028`00000000 IA32_MTRRCAP *msr[000000FE] = 00000000`00000508 IA32_SYSENTER_CS *msr[00000174] = 00000000`00000008 IA32_SYSENTER_ESP *msr[00000175] = 00000000`f8974000 IA32_SYSENTER_EIP *msr[00000176] = 00000000`804def6f nt!KiFastCallEntry (804def6f) IDT Hook lkd> !ms_idt |-----|-----|--------------------|--------------------------------------------------------|---------|--------| | Cre | Idx | Address | Name | Patched | Hooked | |-----|-----|--------------------|--------------------------------------------------------|---------|--------| | 0 | 0 | 0xFFFFFFFF804DFBFF | nt!KiTrap00 | | No | | 0 | 1 | 0xFFFFFFFF804DFD7C | nt!KiTrap01 | | No | | 0 | 2 | 0x000000000000112E | *UNKNOWN* | | No | | 0 | 3 | 0xFFFFFFFF804E015B | nt!KiTrap03 | | No | | 0 | 4 | 0xFFFFFFFF804E02E0 | nt!KiTrap04 | | No | | 0 | 5 | 0xFFFFFFFF804E0441 | nt!KiTrap05 | | No | | 0 | 6 | 0xFFFFFFFF804E05BF | nt!KiTrap06 | | No | | 0 | 7 | 0xFFFFFFFF804E0C33 | nt!KiTrap07 | | No | | 0 | 8 | 0x0000000000001188 | *UNKNOWN* | | No | | 0 | 9 | 0xFFFFFFFF804E1060 | nt!KiTrap09 | | No | | 0 | 10 | 0xFFFFFFFF804E1185 | nt!KiTrap0A | | No | | 0 | 11 | 0xFFFFFFFF804E12CA | nt!KiTrap0B | | No | | 0 | 12 | 0xFFFFFFFF804E1530 | nt!KiTrap0C | | No | | 0 | 13 | 0xFFFFFFFF804E1827 | nt!KiTrap0D | | No | | 0 | 14 | 0xFFFFFFFF804E1F25 | nt!KiTrap0E | | No | | 0 | 15 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 16 | 0xFFFFFFFF804E237F | nt!KiTrap10 | | No | | 0 | 17 | 0xFFFFFFFF804E24BD | nt!KiTrap11 | | No | | 0 | 18 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 19 | 0xFFFFFFFF804E262B | nt!KiTrap13 | | No | | 0 | 20 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 21 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 22 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 23 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 24 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 25 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 26 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 27 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 28 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 29 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 30 | 0xFFFFFFFF804E225A | nt!KiTrap0F | | No | | 0 | 31 | 0xFFFFFFFF806EDFD0 | *UNKNOWN* | | No | | 0 | 42 | 0xFFFFFFFF804DF417 | nt!KiGetTickCount | | No | | 0 | 43 | 0xFFFFFFFF804DF522 | nt!KiCallbackReturn | | No | | 0 | 44 | 0xFFFFFFFF804DF6C7 | nt!KiSetLowWaitHighThread | | No | | 0 | 45 | 0xFFFFFFFF804E0032 | nt!KiDebugService | | No | | 0 | 46 | 0xFFFFFFFF804DEEA6 | nt!KiSystemService | | No | INT 2Eh Hook lkd> !idt 2e Dumping IDT: 2e: 804deea6 nt!KiSystemService Thanks so much for reading, I hope you enjoyed! References BackdoorRustockB On the Cutting Edge: Thwarting Virtual Machine Detection Malware 101 - Viruses Hunting rootkits with Windbg (as always for the great reference). Source
-
Last night I took a quick look at BlackEnergy 2, a rootkit that surfaced in 2010. BlackEnergy 2 was essentially a rewrite of its predecessor as BlackEnergy 2 contains rootkit techniques, process-injection, and encryption. Surprisingly for being a now 'dated' rootkit, there's really not too much accessible (or not buried) reverse kernel-debugging documentation for the rootkit aside from when it was first surfacing. A lot of misc. information pops up throughout very few blogs/forums that are Russian, but that's about it. There's a lot of additional lore behind the rootkit, but I really won't go into that. If you're interested about where the rootkit core came from before it was implemented into BlackEnergy 2, BlackReleaver is the answer! NT Corruption First off, we can view corruption regarding ntokskrnl: lkd> !chkimg -d -v nt Searching for module with expression: nt Will apply relocation fixups to file used for comparison Will ignore NOP/LOCK errors Will ignore patched instructions Image specific ignores will be applied Comparison image path: C:\Symbols\ntoskrnl.exe\41108004214780\ntoskrnl.exe No range specified Scanning section: .text Size: 466369 Range to scan: 804d7580-80549341 804ded5a-804ded5d 4 bytes - nt!KiBBTUnexpectedRange+8 [ 00 ff 09 00:6b a0 c1 01 ] 804e59a1-804e59a5 5 bytes - nt!KeInsertQueueApc (+0x6c47) // Not malicious -- Malwarebytes. [ 8b ff 55 8b ec:e9 e4 45 4e 77 ] Total bytes compared: 466369(100%) Number of errors: 9 !chkimg compares the current loaded executable with the version within the symbol store. This is a helpful command to detect corruptions with images, and especially helpful when dealing with rootkits. The -d parameter displays a summary of all mismatched areas. The -v parameter makes the information verbose. In this case, the -v parameter is optional. As noted above, we have two out-of-range values. We're interested in disassembling nt!KiBBTUnexpectedRange+8, but not nt!KeInsertQueueApc (+0x6c47). nt!KeInsertQueueApc (+0x6c47) as I commented above is in relation to the Chameleon technology from Malwarebytes. I had MWB ARK installed on this VM for testing purposes, so that is where it was spawning from. nt!KiBBTUnexpectedRange+8 Disassembly - Healthy If we disassemble nt!KiBBTUnexpectedRange+8 on a system not infected with BlackEnergy 2, we should expect similar results: lkd> u nt!KiBBTUnexpectedRange+8 nt!KiBBTUnexpectedRange+0x8: 804ded5a 00ff add bh,bh 804ded5c 0900 or dword ptr [eax],eax 804ded5e 0bc0 or eax,eax 804ded60 58 pop eax 804ded61 5a pop edx 804ded62 8bec mov ebp,esp 804ded64 89ae34010000 mov dword ptr [esi+134h],ebp 804ded6a 0f8490020000 je nt!KiFastCallEntry+0x8d (804df000) nt!KiBBTUnexpectedRange+8 Disassembly - Corrupted If we disassemble nt!KiBBTUnexpectedRange+8 on a system that has been infected with BlackEnergy 2, we should expect similar results: lkd> u nt!KiBBTUnexpectedRange+8 nt!KiBBTUnexpectedRange+0x8: 804ded5a 6ba0c1010bc058 imul esp,dword ptr [eax-3FF4FE3Fh],58h 804ded61 5a pop edx 804ded62 8bec mov ebp,esp 804ded64 89ae34010000 mov dword ptr [esi+134h],ebp 804ded6a 0f8490020000 je nt!KiFastCallEntry+0x8d (804df000) 804ded70 8d15509b5580 lea edx,[nt!KeServiceDescriptorTableShadow+0x10 (80559b50)] 804ded76 8b4a08 mov ecx,dword ptr [edx+8] 804ded79 8b12 mov edx,dword ptr [edx] So, why do we have corruptions in ntoskrnl and a corrupted nt!KiBBTUnexpectedRange+8 output? It's a side effect of the rootkit creating additional 'fake' service tables. It does this by patching the ETHREAD SystemTable pointer, which allows for things such as user threads to be patched, thread creation notification and service table pointer updating by using PsSetCreateThreadNotifyRoutine, etc. The main use behind creating fake service tables is it gives anti-rootkit software a much harder time (harder back in 2010, at least) detecting its presence. It doesn't just 'hook' and/or modify the SSDT (which as we know would be a big red flag), it instead creates its own fake service tables, and then hooks (acquires?) the following functions: NtDeleteValueKey NtEnumerateValueKey NtEnumerateKey NtOpenKey NtOpenProcess NtOpenThread NtProtectVirtualMemory NtQuerySystemInformation NtReadVirtualMemory NtSetContextThread NtSetValueKey NtSuspendThread NtTerminateThread NtWriteVirtualMemory etc... KTHREAD Structure Given we're adding new/fake service tables, we need applications to be able to access them. This is done by using pointers as discussed above, which is accomplished in the KTHREAD Structure. Every single thread has a pointer to a ServiceTable which is ultimately set by KeInitThread. Additionally, if the thread requires GUI functions within the Shadow SSDT, PsConvertToGuiThread is called. We can dump the KTHREAD Structure: lkd> dt -v nt!_KTHREAD struct _KTHREAD, 73 elements, 0x1c0 bytes +0x000 Header : struct _DISPATCHER_HEADER, 6 elements, 0x10 bytes +0x010 MutantListHead : struct _LIST_ENTRY, 2 elements, 0x8 bytes +0x018 InitialStack : Ptr32 to Void +0x01c StackLimit : Ptr32 to Void +0x020 Teb : Ptr32 to Void +0x0e0 ServiceTable : Ptr32 to Void At this point if you'd like to see the tables, you can use the following command: !for_each_thread ".echo Thread: @#Thread; dt nt!_kthread ServiceTable @#Thread" If you see anything other than KeServiceDescriptorTable or KeServiceDescriptorTableShadow, it's a new/fake ServiceTable. Registry Hiding In order to survive reboots, etc, it hides its registry entry. If you're using Windows' Registry Editor, it won't find the hidden entry. For example, here's our hidden service: lkd> !ms_services [205] | 0x01 | | qtcst | qtcst | SERVICE_RUNNING | \Driver\qtcst If we try and find qtcst with Registry Editor: If we however use a 3rd party registry tool (any will probably work so long as it doesn't use Windows API calls): We catch our culprit and the dropped driver red-handed. The driver renames after each reboot, so if you remove it and don't get the driver+registry entry at once, it'll just re-create with a different name. Main.dll .exe SYS TMP cmd.exe /C b k e r n e l p l g _ d a t a getp v e r s i o n n a m e s l e e p f r e q c m d s p l u g i n s x%s_%X C:\ a d d r t y p e s e r v e r s i c m p _ a d d r b u i l d _ i d str.sys \drivers\ \ \ . \ \ \ . \ G l o b a l \ %s%s { 9 D D 6 A F A 1 - 8 6 4 6 - 4 7 2 0 - 8 3 6 B - E D C B 1 0 8 5 8 6 4 A } main.dll .bdata {3D5A1694-CC2C-4ee7-A3D5-A879A9E3A623} POST %.2X & = bid nt %d cn ln id ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ Content-Type: application/x-www-form-urlencoded _TEST_ .dll user32.dll advapi32.dll wininet.dll ws2_32.dll DispatchCommand DispatchEvent GetLastError GetCurrentProcessId ExitThread CloseHandle KERNEL32.dll wsprintfA USER32.dll CoCreateInstance CoInitializeEx ole32.dll OLEAUT32.dll WS2_32.dll RtlUnwind InterlockedExchange VirtualQuery main.dll ConfAllocGetTextByNameA ConfAllocGetTextByNameW ConfGetListNodeByName ConfGetNodeByName ConfGetNodeTextA ConfGetNodeTextW ConfGetPlgNode ConfGetRootNode DownloadFile PlgSendEvent RkLoadKernelImage RkProtectObject SrvAddRequestBinaryData SrvAddRequestStringData Main.dll is the payload that is injected via trusted svchost. It contains as you can see a lot of readable stings, like str.sys for example. We can see str.sys in action here: Overall, this rootkit was certainly a step up from most SSDT hooking/modification rootkits at the time. It can be a pain in the ass to remove if you don't kill everything properly : ) Thanks for reading. References Black Energy 2.1+ BlackEnergy Version 2 Analysis Source
-
Over the past few weeks it seems left and right there's Regin this, Regin that. I am not going to do a detailed analysis and discuss its stages and what have you, as there are various/informative in-depth whitepapers, etc. To name a few: Symantec, Symantec. Kaspersky, Kaspersky. F-Secure. In my opinion, Regin is your typical malware that expands outside of the reverse engineer/security community due to its original goal. Journalists or researchers with little kernel-level knowledge/background get a hold of it and before you know it, it's the next biggest sophisticated piece of malware and all that matters is PR. At this point, writing accurate and detailed articles doesn't matter anymore. What am I referring to, and what will I instead talk about with Regin? Secret Malware in European Union Attack Linked to U.S. and British Intelligence. Let's quickly talk about a short few things the whitepapers haven't mentioned (as far as I am aware), and the above article. Respectfully, I have absolutely no idea who reviewed the above article before it was pushed. You have to wonder if The Intercept rushed like hell to publish this article because Symantec released their whitepaper and didn't care about what half of it even said. Note the dates: There's a lot of strange and irrelevant information in that article you can pick at, but the absolute best is: This Regin driver recurrently checks that the current IRQL (Interrupt Request Level) is set to PASSIVE_LEVEL using the KeGetCurrentIrql() function in many parts of the code, probably in order to operate as silently as possible and to prevent possible IRQL confusion. This technique is another example of the level of precaution the developers took while designing this malware framework. Since its publication date this has yet to have been changed, so I guess they don't care after all about its inaccuracies. Anyway, if it's not a surprise, calling KeGetCurrentIrql over and over again throughout the code is just a PAGED_CODE macro. It has absolutely nothing to do with stealth, and PASSIVE_LEVEL doesn't automatically imply obfuscation or stealth. For an example, here's an excerpt from db405ad775ac887a337b02ea8b07fddc (kernel driver - stage 1). call KeGetCurrentIrql test al, al jnz short loc_FDEFAA3D push dword ptr [esi] ; Handle call ZwClose test eax, eax jnz short loc_FDEFAA3D push 18h push ebx push esi call sub_FDEFA2EC add esp, 0Ch mov bl, 1 Again taking a look at db405ad775ac887a337b02ea8b07fddc, there's another interesting tidbit throughout the code: push 43726150h push 20h push edi call ds:ExAllocatePoolWithTag The above is the kernel mode driver's pool tag, the # of bytes to allocate for the memory request, the pool type, and finally its call to ExAllocatePoolWithTag allocate pool memory. Okay, so what's the big deal? If we convert the pool tag operand to a character, we get the following result: push 'CraP' push 20h push edi call ds:ExAllocatePoolWithTag The pooltag is CraP : ) This is probably how many of us feel about this malware being so hyped by the media. There are of course others throughout the code, for example: push 'CraP' push eax push 1 call ds:ExAllocatePoolWithTag Overall, I guess the moral is to take time to get as much accurate information as you can for your articles. I cannot speak for anyone but myself, but as someone with a love for reverse engineering, malware, and debugging, I appreciate in-depth whitepapers and articles that provide thorough analysis. If all you're worried about is competition for views and hyping malware, chances are you're not going to appeal to the people who really care about the written content. PS: Thanks to KernelMode as always for the hilarious discussion. Source
-
Introduction For a long time malware has targeted web data such as site logins. A malicious application could intercept socket functions within a web browser and scan for HTTP headers in order to retrieve HTTP data, however as HTTPS (HTTP Secure) became more widespread, it caused a problem. HTTPS is built on top of the TLS/SSL cryptographic protocols and is designed to prevent MITM (man-in-the-middle) attacks, before the HTTP request is sent to the server it is encrypted using TLS/SSL, this means that any malware intercepting socket functions would receive encrypted data it could not read. The solution: Formgrabbers. Web Browser Basics Web browsers are made up of different APIs, the ones we need to know about are HTTP, Crypto and Socket. As illustrated by the above image, the HTTP API is layered on top of the Crypto and Socket APIs. The web browser can call a function in the HTTP API to send a HTTP(S) Request. The HTTP API will handle the request differently depending on if it's HTTP or HTTPS. If the request is HTTP the HTP API will use the Socket API to send the request to the server. If the request is HTTPS the HTTP API will use the Crypto API to encrypt the request with TLS/SSL then use the Socket API to send it. In the case of Internet Explorer, the HTTP API would be WinInet, the Crypto API would be Secure32 and the Socket API would be Winsock. A malicious application could intercept the Socket API to retrieve HTTP data, then intercept the Crypto API to retrieve HTTPS data before it is encrypted, but that would require intercepting at least 2 function in the browser, on top of that: different browsers use different APIs so that would further complicate things. Formgrabbers Eventually malware developers worked out that they could locate and intercept the HTTP API directly, although this proves difficult in some browsers it offered benefits: Not only would the malware not have to intercept 2 different functions in 2 different APIs, but by intercepting the HTTP API, the malware would be able to receive only HTTP(S) data and not have to worry about other data the browser may send or encrypt. In order to intercept the relevant function in the HTTP API, the formgrabber would use inline hooking to: redirect the function to one within the formgrabber that would check and log the data, then transfer execution flow back to the relevant HTTP API function to complete the request. Source
-
Last night i had this idea that ransomware and other "stab you in the face then steal your wallet" types of malware are likely a result of the antivirus industry becoming better at dealing with malware. It sounds like a crazy claim, but with a little explaining I think most people will see my point. Botnets Are Hard Work C&C IP and DNS blacklisting Large public databases of IP addresses and domains associated with botnet control servers are updated frequently; Some firewalls use these databases to prevent malware connecting to the control servers, ISPs use them to suspend offending servers, and registrars to suspend offending domains. For a botmaster blacklisted IPs usually mean having to purchase more or even move server, if all the domains associated with the botnet are suspended the botmaster would lose total control of all the bots. Monetizing Generating an income can prove challenging: As soon as anti-virus blogs start monitoring a botnet, legitimate companies want nothing to do with it (this usually leads to shady dealings on underground forums). Crypting Currently it only takes a few days for a file to be detected by multiple anti-viruses, for files being distributed by known botnets, a sample can be detected by multiple anti-viruses in a few hours. Contrary to popular belief: nearly all usermode rootkits and most kernelmode rootkits cannot prevent anti-viruses removing their files (even if a reboot is required); once a sample is detected the botmaster has until the user or anti-virus reboots the computer to update the file with an undetected one, or the computer is released from their control. As a result of fast virus signature generation someone maintaining a large botnet would need to update all the bots with a non-detected exe at least once a day or risk losing bots. Takedowns Recently botnet takedowns have been gaining popularity. Most of the large botnets take a severe beating for researchers and law enforcement (which costs the botnet owners time and money), even peer-to-peer botnets aren't safe due to the ever growing resource pool under the control of malware researchers. Ransomware To an extent ransomware operations are similar to botnets: The malware spreads across various vectors (email, exploit packs, warez), requires the executable to be undetected by anti-viruses in order to improve chance of successful infection, and sometimes even phones home to a command and control server; however, ransomware works in a way that solves the problems highlighted with botnets. Ransomware families such a winlockers do not require a C&C server, once a computer is infected the system is locked and the victim is forced to pay a set amount in order to receive an unlock code. Cryptolockers encrypt a users files and required the user to buy a decryption key in order to regain access, once the files are encrypted there is no way to decrypt them without paying for the decryption key. Most cryptolockers store the decryption key on the C&C server, so taking it down only prevents victims from retrieving their files. Forcing a victim to pay an upfront ransom of between a few and a few hundred dollars could potentially make more money than the computer would have made in a whole year as part of a botnet. Once the victim has paid the computer is no use to the group running the scheme and it can be disinfected; this removes the need for keeping the computer up to date with undetected executables and trying hard to hide the presences of the malware. Conclusion As you can see most ransomware works on a principal of infecting a victim, forcing them to hand over money, then getting off the computer as quickly as possible; This already hinders malware removal efforts, but if the ransomware has encrypted the files removal is entirely pointless (the victim will have no way to get their files back). As the anti-virus industry advances and botnets get harder and harder to maintain, i imagine it won't be uncommon to see much more dangerous and low maintenance malware that revolves around aggressively extorting money from victims as quickly as possible. Source
-
I was first made aware of Zorenium bot at the start of November last year by a friend on twitter (R136a1). There were no actual sales threads, just a discussion in IRC and a pastebin post detailing some features (Zorenium 1.0 - Pastebin.com). After being sent a sample, I decided not to write an analysis due to the fact the code was incomplete, of very little interest, and low quality. The bot itself is all over virustotal and similar sites, so collecting samples was easy, however; there are no samples from any later than December 2013, which is when the author was said to have discontinued the bot (Samples Here). Looking at the samples we can tell 2 things: there are 2 different PDB paths which indicates 2 different computers (possibly 2 developers) and the bot is in very early stages of development. Code changes significantly from sample to sample, but all the samples only show very basic IRC and HTTP C&C code and incredibly limited features. The pastebin claims the bot has been worked on "night and day" since December 2012, which is something you should keep in mind. Yesterday some new pastebin posts were picked up and blogged about by Sensecy, before the article found its way onto the infamous threatpost blog (Original Blog Post, ThreatPost, Paste (December), Paste (March)). What's interesting about these posts is they imply the bot has gone from a barely functional HTTP/IRC bot, to a fully fledged peer-to-peer banking bot that runs on Android, IOS, Linux and Windows. If this bot is real, it would likely be the most advanced trojan ever, however; there's a few problems with some of the claims (in the pastebin and sensecy's article). "Zorenium, a relative of Betabot" - Sensecy's Blog Post When asked about betabot's relation to Zorenium, this was the betabot developers response: <User> How is it related to BetaBot? <Betabot Dev> i have no idea <Betabot Dev> it's not even real <Betabot Dev> the guy never completed it, as he said himself "we’ve also updated the rootkit, too a new version of the unreleased - TDL4 rootkit" The TDL rootkit suddenly stopped updating a few years ago, which suggests the team are either retired or in jail. It's hard to believe that the team would resurface to sell an unreleased version of their bootkit to some guys who are selling a bot for £2000 GBP via pastebin. "Zorenium will now run on Ios 5-7 Zorenium will also run on most debian platforms as well as the latest android ipad tablets" It's physically impossible for malware to run on Linux, IOS and windows. If you were somehow able to compile all the code required for the 3 different operating systems into a single executable, how would it run? It might be possible in a cross-platform language like java, but Zorenium claims to be coded in C++ and compiled with Microsoft Visual Studio cl.exe (a windows C/C++ compiler). "After alot of work, testing and money spent. We can now make the victims believe there SYSTEM is being shutdown on victim input, Thus means zorenium will throw fake images to make the user believe hes shutting down his machine. Zorenium will then shut down the screen to standby mode ( until the Poweron button is initialized ) Whilst the user thinks he or she is shutting down there machine, we can stop (Delay) the CPU Fan, and other fans, which will make a racket making the user believe his or her system is still running. remember this method is not 100% Guaranteed to overheat the victims computer, causing it to force shutdown" Wat. Not only does this make little sense, but I'm pretty sure there is no universal way to control PC fans. Some motherboards offer software to do it, but the software differs greatly. "***THERE ARE STILL MORE I NEED TO ADD TO THIS DOCUMENTION, BUT WITH PLAYING CATCH ME IF YOU CAN WITH THE CYBER TEAM, ITS IMPOSSIBLE TO STAY IN ONE PLACE UPDATING THIS DOCUMENT*** STAY TUNED ***" Some classic attention seeker action right here. Nothing says professional malware developer like running around the country fleeing authorities who are chasing you for a non-existent super bot. -Update- Sensecy has got back to me on my request, the bot is apparently sold on 1 forum and the seller has very little reputation, still not sure of the forum name though. Conclusion Based on the fact that some of the features aren't even possible, none of the samples seen have any moderately advanced features, the only evidence of sales is a pastebin post, and no large security company has picked it up; I'm going to say the whole thing is fake. Obviously I will keep my eyes open for a samples of a new super bootkit banking bot using a private version of TDL4 and speading across windows, linux, android and iOS systems; let's see how long i can hold my breath. Source
-
Some security agencies have been raving about a revolutionary new bot that combines point-of-sales card grabbing (ram scraping) with form grabbing. The bot is actually not very interesting and pretty simple, but the panel is a great deal of fun (thanks to xylitol for getting me interested). By default the panel shows the last 25 connected bots on the index page, not very interesting or helpful feature, but it opens up a whole world of possibilities. To understand what is possible, we need to take a look at the code responsible for adding new bots the the database. From this code we can gather enough information to "impersonate" a bot. The HTTP method is POST, 'mode' must be '1', 'uid' must be a unique number, 'compname' must be a hex encoded string and so must 'osname'. The only difficult part is the fact the panel requires the bot to use a specific user-agent; however, we can find this by reversing a sample of the bot. Here I've put together some code to add fake bots to the pane, thus add entries to the "last 25 connections". Now, what if we decided to be a bit naughty? Let's try and submit HTML code as the bot's computer name. I'm sure this won't work because nobody is that bad at security, right? RIGHT?? Let's see the result... Oh dear... We'll, cool. We can submit HTML / JavaScript but what use can that be? Well we could mess with the botmaster by using javascript to redirect him to fbi.gov, replacing the entire page with rick roll, or modify the statistics. But could we hijack all his bot? Turns out the answer is yes! A quick look at the command page allows us to throw together some code using "XMLHttpRequest()", when executed it will result in an update command being issued to the bot. All we need to do is provide our exe path in urlencoded format. We could pay for hosting to host our script, only a small price to pay for a lot of free bots. Or, we could just use pastebin... All we need to do now is submit javascript to the panel which will run the code from pastebin. Once we run it, when the botmaster logs in he will see this on the statistics page (minus the red block over the ip of course)... The result of him viewing the page will be this.... So looks like revolutionary new malware "Soraya" is a little less than revolutionary when it comes to web security. Anyone with a sample of the bot binary can mess with the botmaster or potentially hijack the entire botnet. Surce
-
A long long time ago (about 10 years in non-internet time) malware developers only had to worry about signature based detection, which could be easily bypasses with polymorphic droppers or executable encryption. To deal with rapidly evolving malware, capable of evading signature detection, HIPS was created. HIPS (Host-based Intrusion Prevention System), sometimes referred to as Proactive Protection or Proactive Defense, is an anti-malware technique designed to detect malware by behavior, and not its file signature. Using kernel mode callback and hooking, HIPS systems can monitor which functions an executable calls, with which parameters, and in what order. By monitoring executable calls the HIPS can get a decent idea of what the executable is trying to do, Ex: Allocating executable memory in a foreign process, followed by creating a thread that resides in the allocated memory; The process is likely trying to inject code. Once the executable tries to perform an action that is deemed malicious, the system can decide what to do based on how common the application is, if it's signed and by whom. For a malicious executable to escape a HIPS, it would have to trick the system into believing it's a legitimate signed application. Due to non-static data within a process, such as absolute addresses, imports, and statically allocated variables; it is not possible to verify the digital signature of a running process. To check a process' signature, the HIPS would have to get the executable file path from the PEB (Process Environment Block) or the section handle, then verify the signature of the file on disk. Zombie Processes The concept of zombie processes is pretty simple: we can create a standard Windows process in a suspended state, then write our malicious code to the processes' memory; the PEB and the EPROCESS structures will still be that of the original process, causing the HIPS to see the now malicious process as a legitimate signed executable (this is not RunPE or dynamic forking, because we don't unmap the original executable and replacing it with our malicious one, as thos can be detected in multiple ways). It's basically PE injection, but with less exposure to functions that would allow the HIPS to detect code injection. CreateProcess returns a handle to the created process and its main thread with full access, so we don't have to call OpenProcess or OpenThread. The main thread is in a suspended state and we know the entry point, so no need to call CreateRemoteThread. Modification to a child process is far less suspicious that a foreign one Injecting the Code A common practice is to call VirtualAllocEx to allocate memory, then use the returned address to relocate the code ready to run at that address. Once the code has been prepared, it can be written to the process with WriteProcessMemory. This is a terrible idea, every HIPS ever expects malware to do that. A better practice used by newer malware (such as Andromeda and BetaBot) is to create as section, then use NtMapViewOfSection to map the section into both the current process and the target process. It's not really possible to know what address the section will be mapped at before mapping it, so this would cause a problem with code that requires relocation. NtMapViewOfSection actually maps the same physical section into both processes (writing the map of the section in the current process will also write the map in the target process), we can simply map the section into both processes then relocate and write the code to the section in the current process, resulting in it also being written to the target process, no WriteProcessMemory needed! Executing the Code There's a few ways to do this, but I'll go over the 2 most common. Use SetThreadContext to change the EAX register (which points to the process entry point) to the entry point of your code. Use WriteProcessMemory to write a jump from the process entry point to your code. Conclusion Once the code is running inside the trusted process, it is likely to have far more freedom as to what it can do without triggering antivirus warnings, the PEB, EPROCESS and Section Handle, all still point to the original process. As always I've included some example code: https://github.com/MalwareTech/ZombifyProcess Source
-
Introduction This analysis is of a new winlocker dropper that was first seen in the wild last month, the binary is 64 bit, packed with MPRESS, and contains 3 local privilege escalation exploits (CVE-2013-3660, CVE-2012-1864, and CVE-2012-0217), as well as the PowerLoader injection method. 2 of the exploits and the powerloader injection were stolen from carberp leak. I, as well as a few others, thought the dropper may be PowerLoader, however I now have my doubts, I will explain why at the end. Data Gathering The first thing the loader does is query some system information, then post it to the command and control server (C&C). The function I have named "PostArch" simply posts the string "x64" to the C&C, the rest of the functions query the version information of the following file: win32k.sys, ntoskrnl.exe, ntkrnlpa.exe, ntkrnlmp.exe, and ntkrpamp.exe, then post it to the command and control. The first header is for the "PostArch" function, the second is for the rest. Any data is url encoded so the file version data is "f=win32k.sys&v=6.1.7600.16617&", this format is used for every file and the last "&" doesn't do anything but the coder appends it anyway. Exploitation The loader will inject into explorer using an x64 version of the infamous Shell_TrayWnd Injection (Explained Here). Once inside explorer the first exploit is executed, if it fail: the next one is executed, and so on. The exploits are as follows: EPATHOBJ::pprFlattenRec (CVE-2013-3660) String Atom Class Name (CVE-2012-1864) (Intel / x64) SYSRET (CVE-2012-0217) Each exploit will try to elevate the process privileges, if successful, a dll will be written to the temporary directory, under the name "dll.dll", then executed (The dll is also packed with MPRESS). Let's take take a look at the dll after unpacking. All that is happening here is the dll makes sure the "fdwReason" parameter of the entry point is "DLL_PROCESS_ATTACH" (The dll is being loaded). Next it gets the full path to the process that the dll is currently loaded in, then signals an event to notify the main process that the load was successful. After this, the filename is extracted from the file path and stored in the RSI register. Let's take a look at what is does with this value. Here the dll checks if the operating system version is 6 and platform id is "VER_PLATFORM_WIN32_NT", which makes sure the OS is Vista+, then attempts to get the process id of its parent, followed by suspending all threads inside the parent process. If any of the following operations fail, it just skips ahead to the next stage. This is the last stage, here the dll extracts and drops a second dll to "C:\Windows\System32\vBszKyhVp.dll". The loader then looks for an svchost process running as "NETWORK SERVICE", opens a handle to the process, allocates some memory inside, writes the dll path to the allocated memory, and calls "RtlCreateUserThread". The thread start address is set to the address of "LoadLibrary" and the parameter set to address of the allocated memory, as a result the thread in svchost will call loadlibrary with the dll path set to the path of the dropped dll, which will cause the process to load the dll. The 2nd dll is responsible for downloading some images and installing a winlocker, it is also packed with MPRESS, I'll probably reverse it and write about it in a part 2. Why I'm not sure this is PowerLoader Basically the code seems too closely related, the first dropper creates an event that is then signaled by the 1st dll that is dropped, the dll also checks what process it is in, which could change based on which exploit was successful. The way that the dll interacts with the dropper makes me think that they were both coded by the same person. As well as this, the dropper sets a registry key with the screen resolution, which is used by the locker to get the correct size screen-lock image, this rules out the 1st dll being part of the PowerLoader dropper. Originally, what made me think it was PowerLoader was the string that said "powerloader". After a while reversing this sample, I realized that the string is probably just referring to the elevation method used, seeming as this code indicates which method was successful (atom exploit, sysret exploit, epathobj exploit, powerloader injection). To me, it seems more likely that this is all part of the same project and most of the primary dropper code was stolen from carberp. Possibly more exploits to come I did notice a few bits of unused code in the dropper that seemed to imply more exploits were on the way. These 2 images make me think the coders are in the process of implementing a user account control bypass, there is a public bypass that exploit auto-elevating processes on windows 7 (sysprep being one of them). Also, earlier in the article i showed 2 checks (one for logonui.exe and one for utilman.exe). The atom exploit (CVE-2012-1864) will result in the dll getting loaded into logonui process, however, none of the exploits seem to load the dll into utilman, which leads me to think they were testing another exploit. Conclusion The Shell_TrayWnd Injection and CVE-2012-1864 + CVE-2012-0217 were both taken from the carberp leak (this is probably the biggest theft of code from the leak that i have seen so far). Because the winlocker component seems interesting, I will likely write a part 2 and reverse it. Thanks to R136a1 for the sample and collaboration on reversing. Source