It has been a while since my last blog post. In this one I'll present my experiment with using AI-assisted coding to build three Rust-based tools that ease my malware analysis workflow. I built them by using a Claude Pro account.
The Malware: Lorem Ipsum
I'll present three tools I built with Claude to analyze the Lorem Ipsum malware. I'm not going into detail about the malware functionality, since it was already covered in the BlueVoyant blog post.
The malware, especially in its latest version, is extremely obfuscated, making static analysis very hard: since IDA is not able to decompile the code, you have to work at the assembly level. I'll show how I was able to extract interesting IOCs from it by using a few dynamic analysis tools.
You can download the sample I used for this blog post from MalwareBazaar. In order to run it, you need the Node.js framework. Once the JavaScript code executes, the malware binary is installed in the C:\ProgramData\Microsoft Edge Updates Helper qZWpLKQXEGaa directory. To analyze it you have to kill the process and then restart it with the tools described below.
Disclaimer: My tools are very similar to other well-known alternatives. I chose to build them because I wanted to experiment with AI-assisted coding while also implementing features that were missing but that I consider useful for my workflow.
Shellcode Analysis — shrun
The first tool I built is shrun, a shellcode-to-executable converter that wraps a raw buffer into a PE file that can be loaded in the debugger. There are many such tools, but I found them to not work properly or to be overly complicated. With shrun I was able to create a PE file with a .text section that is RWX, and that accepts the shellcode allocation address as the first parameter via rcx — a common requirement in the shellcodes I analyze. To create a PE file I run the following command:
C:\Users\User\Desktop>shrun.exe
Usage: shrun.exe <shellcode.bin | hex_string> [32|64]
C:\Users\User\Desktop>shrun.exe shellcode.bin 64
[*] input: \\?\C:\Users\User\Desktop\shellcode.bin
[*] mode: PE64 (64-bit)
[*] payload: 147150 bytes
[*] output: \\?\C:\Users\User\Desktop\shellcode_sh.exe
[*] shellcode: 0x0000000180001000 (= BASE_ADDRESS -> rcx)
[+] done - entry/stub: 0x0000000180024ece
C:\Users\User\Desktop>
Now I can use x64dbg to run my shellcode or analyze it in IDA (you can analyze the shellcode in IDA too, but good luck applying FLIRT signatures 😛).
API Tracing — apiwatcher
There are plenty of programs that do API tracing, such as tiny_tracer or API Monitor. These tools are very useful when the malware is heavily obfuscated and data-flow analysis is the quickest way to understand what it does. The feature I wanted was a CLI program that provides extensive information on the called APIs. So I decided to implement a tool that parses C header files in order to reconstruct each API's function signature. This way, during tracing, parameter names and their values can be captured with additional context. For this reason I built apiwatcher.
It supports many features, such as functions to exclude, functions to include, tracing targets, and so on. For our case, I know that the malware logic is implemented in msvcp140.dll, so I'll trace only calls originating from that DLL, filtering to IAT imports and dynamically resolved functions. Below you can see an example of output:
C:\Users\User\Desktop\apiwatcher-1.0.0>apiwatcher.exe --trace-iat --dll msvcp140.dll -- "c:\ProgramData\Microsoft Edge Updates Helper qZWpLKQXEGaa\Microsoft Edge Updates Helper.exe"
__ _ _ __ (_)__ __ __ _ _ ___ _ ___ _ __
/ _` | '_ \(_)\ \ /\ / / / _` || |_ / __|| |_ / _ \| '__|
| (_| || |_) || | \ V V / | (_| || __| (__| '_ \| __/| |
\__,_|| .__/ |_| \_/\_/ \__,_||_| \___|_| |_| \___|_|
|_| |_| |_|
v1.0.0 | Windows API call tracer
[*] Using default exclusion file 'exclusions.txt'
[*] 141 exclusion pattern(s) loaded
[*] Using default inclusion file 'inclusions.txt'
[*] 7 inclusion pattern(s) loaded (override exclusions)
[defs] fileapi.h: 92 function(s), 5 typedef(s), 31 macro(s) expanded
[defs] libloaderapi.h: 32 function(s), 10 typedef(s), 15 macro(s) expanded
[defs] memoryapi.h: 58 function(s), 7 typedef(s), 7 macro(s) expanded
[defs] ntifs.h: 709 function(s), 617 typedef(s), 276 macro(s) expanded
[defs] processthreadsapi.h: 82 function(s), 15 typedef(s), 3 macro(s) expanded
[defs] string.h: 40 function(s), 0 typedef(s), 1 macro(s) expanded
[defs] synchapi.h: 61 function(s), 10 typedef(s), 22 macro(s) expanded
[defs] winhttp.h: 40 function(s), 28 typedef(s), 33 macro(s) expanded
[defs] WinInet.h: 171 function(s), 79 typedef(s), 125 macro(s) expanded
[defs] winsock.h: 44 function(s), 33 typedef(s), 78 macro(s) expanded
[defs] winsock2.h: 105 function(s), 171 typedef(s), 133 macro(s) expanded
[*] Loaded 1394 function definition(s) from 'defs'
[*] IAT-trace mode: hooking EXE imports + GetProcAddress-resolved functions
[+] PID 6516 - 102 IAT hook(s) from Microsoft Edge Updates Helper.exe
[+] Attached to PID 6516 - waiting for initial breakpoint...
[+] PID 6516 - hooking GetProcAddress @ 0x7ff89565b1d0 (kernel32.dll)
[+] PID 6516 - hooking GetProcAddress @ 0x7ff89462abc0 (KernelBase.dll)
[+] GetProcAddress(ntdll.dll.RtlDisownModuleHeapAllocation) -> 0x7ff896ecfa30 - hooking
[+] GetProcAddress(KernelBase.dll.InitializeCriticalSectionEx) -> 0x7ff89465be60 - hooking
[+] GetProcAddress(KernelBase.dll.FlsAlloc) -> 0x7ff89466ac60 - hooking
...
[+] GetProcAddress(winhttp.dll.WinHttpSetOption) -> 0x7ff88d2f7ce0 - hooking
[+] GetProcAddress(winhttp.dll.WinHttpSetTimeouts) -> 0x7ff88d2f8420 - hooking
By default the trace is saved in the CSV file apiwatcher.csv. Below you can see an extract of the generated file:
timestamp,pid,tid,retaddr,caller_image,bp_addr,target_image,target_routine,params,retval
...
1780735593.201378,6516,7520,0x7ff87d6e2d68,msvcp140.dll,0x7ff89565b1d0,kernel32.dll,GetProcAddress,hModule=0x00007ff896e50000 lpProcName=0x00007ff87d6e2d59:"strcmp",0x00007ff896ee0ed0
1780735594.747193,6516,7520,0x7ff87d6e2dc5,msvcp140.dll,0x7ff89565b1d0,kernel32.dll,GetProcAddress,hModule=0x00007ff896e50000 lpProcName=0x00007ff87d6e2db6:"strlen",0x00007ff896ee1050
1780735596.315369,6516,7520,0x7ff87d6e2e61,msvcp140.dll,0x7ff89565b1d0,kernel32.dll,GetProcAddress,hModule=0x00007ff895640000 lpProcName=0x00007ff87d6e2e4c:"LoadLibraryA",0x00007ff895660800
1780735597.852891,6516,7520,0x7ff87d6e2faa,msvcp140.dll,0x7ff896ee0ed0,ntdll.dll,strcmp,_Str1=0x00007ff87d71f0bc:"gentle" _Str2=0x00007ff87d755132:"though42",0xffffffff
1780735597.853478,6516,7520,0x7ff87d6e2faa,msvcp140.dll,0x7ff896ee0ed0,ntdll.dll,strcmp,_Str1=0x00007ff87d71f0c3:"hush" _Str2=0x00007ff87d755132:"though42",0xffffffff
...
1780738174.437364,6516,7520,0x7ff87d7563f0,msvcp140.dll,0x7ff895664c80,kernel32.dll,CreateMutexA,lpMutexAttributes=0x0000000000000000 bInitialOwner=0x00 lpName=0x00007ff87d75a524:"bf428ad4-cb18-44b1-87f7-7047da02c592",0x00000170
1780738174.438104,6516,7520,0x7ff87d756481,msvcp140.dll,0x7ff896ed1750,kernel32.dll,AddVectoredExceptionHandler,arg0=0x0000000000000001 arg1=0x00007ff87d757132 arg2=0x00000000ffffffff arg3=0x0000000000000001,0x0000021a94e3af50
...
1780738185.621205,6516,7520,0x7ff87d758822,msvcp140.dll,0x7ff895664e60,kernel32.dll,CreateFileA,lpFileName=0x00007ff87d75a525:"f428ad4-cb18-44b1-87f7-7047da02c592" dwDesiredAccess=0x80000000 dwShareMode=0x00000001 ...,0x00000054
1780738185.687583,6516,7520,0x7ff87d758898,msvcp140.dll,0x7ff895665090,kernel32.dll,GetFileSize,hFile=0x00000054 lpFileSizeHigh=0x0000000000000000,0x00014aab
1780738185.688160,6516,7520,0x7ff87d7589b0,msvcp140.dll,0x7ff8956651f0,kernel32.dll,ReadFile,hFile=0x00000054 lpBuffer=0x0000021a96a10080 nNumberOfBytesToRead=0x00014aab ...,0x01
1780738185.824290,6516,7520,0x7ff87d7589d9,msvcp140.dll,0x7ff895664bf0,kernel32.dll,CloseHandle,arg0=0x0000000000000054 ...,0x0000000000000001
...
1780740347.222177,6516,7520,0x7ff87d757ca4,msvcp140.dll,0x7ff88d2f1e20,winhttp.dll,WinHttpOpen,pszAgentW=L"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:143.0) Gecko/201001" dwAccessType=0x00000000 ...,0x0000021a94e50120
1780740347.224994,6516,7520,0x7ff87d757d48,msvcp140.dll,0x7ff88d2dfac0,winhttp.dll,WinHttpConnect,pswzServerName=L"loginrestforest.com" nServerPort=0x01bb ...,0x0000021a94e5bbf0
1780740347.227423,6516,7520,0x7ff87d757e26,msvcp140.dll,0x7ff88d2fa2d0,winhttp.dll,WinHttpOpenRequest,pwszVerb=L"POST" pwszObjectName=L"/api/init/bf428ad4-cb18-44b1-87f7-7047da02c592" ...,0x0000021a94e776e0
1780740347.231475,6516,7520,0x7ff87d757ef4,msvcp140.dll,0x7ff88d2f8950,winhttp.dll,WinHttpAddRequestHeaders,lpszHeaders=L"Content-Type: image/jpeg" ...,0x01
1780740347.232000,6516,7520,0x7ff87d757f79,msvcp140.dll,0x7ff88d2f9040,winhttp.dll,WinHttpSendRequest,...,0x00
1780740369.157199,6516,7520,0x7ff87d758075,msvcp140.dll,0x7ff88d2f9930,winhttp.dll,WinHttpReceiveResponse,...,0x00
...
Since apiwatcher supports dropping arbitrary .h files in the defs directory to enhance the output, from the trace you can extract very useful information: the mutex name, the C2 hostname (loginrestforest[.]com), the API endpoint pattern (/api/init/<UUID>), and the fake Content-Type: image/jpeg header.
Network Traffic Monitoring — argus
The last tool I want to describe is very similar to FakeNet, but with enhanced capabilities: argus. I decided to implement this tool to ease malware traffic analysis. I wanted something that logged all requests and responses, including HTTPS, with the ability to modify them on the fly. Argus uses the same WinDivert-based interception mechanism as FakeNet but also supports forwarding to the real server.
Its configuration is quite extensive, so please refer to the official documentation for a complete description. In order to effectively use argus, you have to install in your sandbox the certificate used to intercept HTTPS traffic. A default certificate is included in the package, but if you delete it, argus will create a new one when started. Below you can see a few screenshots showing how to install the certificate in your Trusted Root store.
In my case I want to forward the requests to the C2 server in order to capture both requests and responses. I modify configs/default.ini and add to the [HTTPSListener] section the following line:
Passthrough: *
This instructs argus to forward all requests to the real server. Then I run argus followed by the malware:
PS C:\Users\User\Desktop\argus-1.1.0> .\argus.exe
_ ____ ____ _ _ ____
/ \ | _ \ / ___|| | | / ___|
/ _ \ | |_) || | _| | | \___ \
/ ___ \| _ < | |_| | |_| |___) |
/_/ \_\_| \_\ \____|\___/ |____/
Network traffic interception tool for malware analysis | v1.1.0
2026-06-06 03:26:24 INFO Loading configuration from: configs/default.ini
2026-06-06 03:26:24 INFO Starting Argus on 0.0.0.0
2026-06-06 03:26:24 INFO Request logging -> capture
2026-06-06 03:26:24 INFO Starting all listeners...
Starting listeners:
* HTTPListener on 0.0.0.0:18080 (intercepts :80) [TCP]
* HTTPSListener on 0.0.0.0:18443 (intercepts :443) [TCP/SSL]
[Argus HTTPS] Using CA certificate from configs\argus-ca.crt
2026-06-06 03:26:24 INFO All listeners started (2 total)
2026-06-06 03:26:24 INFO Diverter: active - full bidirectional NAT enabled
Argus is running. Press Ctrl+C to stop.
2026-06-06 03:26:45 INFO Diverter: [SearchApp.exe (PID 8176)] 192.168.92.130:50266 -> 2.22.248.140:443 intercepted
2026-06-06 03:26:47 INFO Diverter: [svchost.exe (PID 3388)] 192.168.92.130:50283 -> 23.206.246.162:80 intercepted
2026-06-06 03:26:47 INFO Diverter: [svchost.exe (PID 3388)] 192.168.92.130:50282 -> 184.25.52.64:443 intercepted
2026-06-06 03:26:52 INFO Diverter: [Microsoft Edge Updates Helper.exe (PID 1196)] 192.168.92.130:50304 -> 92.118.126.178:443 intercepted
[HTTPSListener] 127.0.0.1:50304 -> 92.118.126.178:443 PASSTHROUGH [Microsoft Edge Updates Helper.exe (PID 1196)]
...
2026-06-06 03:27:13 INFO Diverter: [Microsoft Edge Updates Helper.exe (PID 1196)] 192.168.92.130:50320 -> 146.19.49.91:443 intercepted
[HTTPSListener] 127.0.0.1:50320 -> 146.19.49.91:443 PASSTHROUGH [Microsoft Edge Updates Helper.exe (PID 1196)]
2026-06-06 03:27:34 INFO Diverter: [Microsoft Edge Updates Helper.exe (PID 1196)] 192.168.92.130:50326 -> 144.217.220.118:443 intercepted
[HTTPSListener] 127.0.0.1:50326 -> 144.217.220.118:443 PASSTHROUGH [Microsoft Edge Updates Helper.exe (PID 1196)]
...
All traffic is captured in the capture folder, following the pattern capture/<PROCESS NAME>/<PID>/<HANDLER NAME>/<LOG FILE>.log. From the captured data I can see that the malware starts communication with a few C2 servers using the URL pattern /api/init/<UUID>, followed by a request to another server likely used as a dead-drop, before cycling back to the same pattern. This analysis is consistent with the apiwatcher trace.
Conclusion
My experience with AI-assisted coding can be summarized in a few points:
- Domain expertise is still essential. You need to guide Claude during development — it won't figure out your specific requirements on its own.
- Resist feature creep. LLMs tend to be very verbose and to suggest a lot of cool features. Resist saying yes, as they tend to overestimate their usefulness 🙂
- Say goodbye to code paternity. As mrexodia pointed out, you lose ownership in a way that's hard to describe. You care about the code, but it's not entirely yours anymore 🙂