## **TTD Overview** Per previous static analysis of [[FIN6 - Grateful 'FrameworkPOS']], functionality related to persistence, memory scanning, and exfiltration for credit card scanning was able to be observed. Unfortunately with static analysis it can be quite time consuming, and leave room for some uncertainty regarding function input and code flow. Time Travel Debugging(TTD) combined with Code Coverage can be used to speed up this process. ###**Creating A TTD Trace and Code Coverage File** Creating a TTD trace can be done within Binary Ninja itself or WinDbg. To include code coverage within the trace, the trace will be created within WinDbg. 1. [[Creating a TTD Trace for Binary Ninja]] 2. [[Creating Code Coverage File (bncov)]] ## **TTD Analysis** Loading within TTD we can attempt to follow the trace to determine the flow of the program. Setting a breakpoint at Main, this can be walked to determine the initial path the malware is going to take. Combined with bncov we can visualize the code coverage as we walk the TTD trace. Note: For some reason High Level IL was not highlighting code coverage. The Disassembly view was used to examine the code coverage of this TTD trace. ![[Pasted image 20250919215723.png]] After navigating to the breakpoint, the Mini Graph within the function displays the path the trace took. ![[Pasted image 20250919215816.png]] When checking the disassembly, within the Main Function, we can see a series of IF statements being evaluated. Through bncov we can see the exact path within the function that is taken. Based off the highlighted coverage, the malware appears to take the path of mw_CheckAdminPrivs and then falling into an ELSE statement where mw_Create_HamachiService and mw_Start_Service is called. It's worth noting this binary was run with no arguments and not in admin context. Thus we can confer from this, with no arguments supplied to the binary, this will be the code execution flow that is taken. ![[Pasted image 20250919215951.png]] To validate this, we can continue to step through the trace where we will eventually end up at the mw_Create_HamachiService. ![[Pasted image 20250919220027.png]] Once the trace hits the mw_Create_Hamachi_Service, this can be stepped into. After reaching the CreateServiceA Windows API we can check the High Level IL to identify values that are being passed into the function call. ![[Pasted image 20250919220243.png]] While Binja does a good job of showing what some of these values are in the disassembly, the WinDbg debugger within Binja can show what is being pushed onto the stack. ###### ***Checking for CreateServiceA API Calls:*** ``` dx -g @$cursession.TTD.Calls("advapi32!CreateServiceA*").Select( c => new {TimeStart = c.TimeStart, Function = c.Function, Parameters = c.Parameters,ReturnAddress = c.ReturnAddress}) ``` ![[Pasted image 20250919220450.png]] With the CreateServiceA showing a TimeStart of CB:1203, this can be passed into the time travel command within WinDbg to travel to that point in time within the trace. ###### ***Time Traveling to Point in Time*** ``` !tt CB:1203 ``` ![[Pasted image 20250919221017.png]] Looking at the MSDN Documentation for CreateServiceA, we can see the number of arguments within the API. ```C++ SC_HANDLE CreateServiceA( [in] SC_HANDLE hSCManager, [in] LPCSTR lpServiceName, [in, optional] LPCSTR lpDisplayName, [in] DWORD dwDesiredAccess, [in] DWORD dwServiceType, [in] DWORD dwStartType, [in] DWORD dwErrorControl, [in, optional] LPCSTR lpBinaryPathName, [in, optional] LPCSTR lpLoadOrderGroup, [out, optional] LPDWORD lpdwTagId, [in, optional] LPCSTR lpDependencies, [in, optional] LPCSTR lpServiceStartName, [in, optional] LPCSTR lpPassword ); ``` Seeing there is 13 variables within the function, the stack can be displayed from esp+4(esp+4 is used because esp contains the return address pushed by the call function) with 13 DWORDS. ###### ***Display the Stack*** ``` dd /c 1 esp+4 L13 ``` ![[Pasted image 20250919221310.png]] Looking at DWORD's 4-6 provide insight into type of service and the permissions being supplied. Within [[https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-createservicea|MSDN Documentation]] the values can be mapped to: + 0x000f01ff = SERVICE_ALL_ACCESS + 0x00000010 = SERVICE_WIN32_OWN_PROCESS +0x00000002 = SERVICE_AUTO_START Additionally, the memory address can be dereferenced to display any potential obfuscated values that are being passed. Looking at stack argument 8 (ESP+20), the memory address when dereferenced shows the path name of the executable being supplied to the service to autostart. ###### ***Dereferencing the Pointer*** ![[Pasted image 20250919221340.png]] Alternatively, the binary path is also contained with the ecx register when examining the disassembly within the TTD Trace ![[Pasted image 20250919221429.png]] Setting a breakpoint at the call to CreateServiceA will allow us to see the binary being supplied for the persistence within the ecx register. ![[Pasted image 20250919221449.png]] #### **Credit Card Code Execution Flow** The crux of the malware is the credit card stealing and exfiltration over C2. Per looking at the code coverage map, the credit card stealing functions will never hit when supplying no command line options and running in user context. ![[Pasted image 20250920092749.png]] In order to get to the credit card execution, WinDBG needs to be attached to the running process after persistence has been established. From there, a new trace can be taken and imported into Binary Ninja. After loading the new trace in, a breakpoint can be set at the entry point of the credit card detection function. As Processes are scanned, the mw_Credit_Card_Detection function is called to validate if there is any valid credit card functions within memory. In this case, there was no dummy Credit Card data on the malware analysis VM. Thus it's expected in this scenario when the detection function is reached it will exit. Within the TTD we can see the value in EAX of 0xffffffff compared to 0x0 causing the exit routine for that process to be reached. ![[Pasted image 20250920094024.png]] This routine cycles back through the scanning routine where it takes additional process snapshots and runs mw_Credit_Card_Detection against those processes looking for any new credit card numbers on the machine. Because a credit card number is not found, the bulk of the code related to Credit Card Identification, DNS Exfiltration, and Credit Card Track Identification is skipped over. Code coverage demonstrates the path taken when no Credit Cards are identified, with the path in Blue below containing the code related to Credit Card fingerprinting and exfiltration. ![[Pasted image 20250920094101.png]]