• Investigation Log
- Connected to IDA session, captured module hashes, enumerated exports (DllEntryPoint, Crash) to frame analysis scope.
- Decompiled Crash → LaunchConfiguredIec104Sessions:0x100014e0, observed config parsing call and thread fan-out via CreateThread (0x10001547), then traced worker entry StartAddress to identify IEC‑104 workflow.
- Analyzed ParseIec104ConfigFile:0x10001610; confirmed _wfopen (0x10001674) and _fgets usage, mapped keywords target_ip, target_port, sequence, stop_comm_service, command_type, operation, shift, range, uselog at refs 0x100017B0–0x10002004 to per-session structure fields.
- Inspected RunIec104SessionWorker:0x10002FE0; documented service-kill logic (OpenProcess 0x1000303D / TerminateProcess 0x10003046), IEC-104 connect (Iec104Connect 0x10003079), handshake (SendStartupSequence 0x1000309D), sequence dispatch (range 0x1000315D, shift 0x100031AE) and command emission (IssueSingleCommand calls at 0x1000331A/0x1000335E/0x100034E6/0x10003507).
- Reverse engineered transport helpers: Iec104Connect (WSAStartup 0x100023E9, socket 0x10002499, connect 0x100024EB), TransmitApdu (send 0x10002642), ReceiveApdu (recv 0x10002730), ProcessIncomingApdus (response parsing, SendSupervisoryFrame 0x100029F2).
- Mapped support routines (APCI/ASDU encoders, logging, defaults) and applied descriptive renames to every touched function for traceability.
Function Mapping Table
Original Name | New Name | Address | Brief Description
Crash | LaunchConfiguredIec104Sessions | 0x100014e0 | Entry export: parse config, spawn worker threads, wait on handles.
StartAddress | Iec104ClientThread | 0x100015e0 | Thread stub: announce IEC-104 target, hand off to worker.
sub_10001610 | ParseIec104ConfigFile | 0x10001610 | Reads tokenised config, populates 66 kB session records/vectors.
sub_10002FE0 | RunIec104SessionWorker | 0x10002fe0 | Core loop: kill optional service, connect IEC-104, execute sequence.
sub_100023C0 | Iec104Connect | 0x100023c0 | Resolve host, open TCP socket, apply 15 s timeout, return handle.
sub_10002560 | TransmitApdu | 0x10002560 | Build APDU bytes, manage send counters, call send, log failures.
sub_100026D0 | ReceiveApdu | 0x100026d0 | Repeated recv, accumulate into session buffer, set state flags.
sub_10002830 | ProcessIncomingApdus | 0x10002830 | Parse inbound frames, trigger logging, schedule supervisory/U-frames.
sub_10002B40 | SendSupervisoryFrame | 0x10002b40 | Emit S-frame handshake, expect response via ReceiveApdu.
sub_10002C30 | SendControlUFrame | 0x10002c30 | Send U-frame control (STARTDT/STOPDT/TESTFR) for connectivity.
sub_10002D30 | IssueSingleCommand | 0x10002d30 | Craft IEC type 45 single commands using config qualifiers.
sub_10002EB0 | FindProcessIdByName | 0x10002eb0 | Snapshot processes, case-insensitive match, return PID.
sub_10002F80 | AppendSessionLog | 0x10002f80 | Optional file logging with rollover/new-file modes.
sub_10003660 | LogApduDetails | 0x10003660 | Console formatter for IEC traffic; decodes cause/type IDs.
sub_10001230 | BuildApduBuffer | 0x10001230 | Serialize APCI/ASDU headers into outbound buffer.
sub_100012B0 | ParseApduBuffer | 0x100012b0 | Validate inbound APDU, forward to ASDU parser.
sub_10001180 | AllocateApduContext | 0x10001180 | Allocate APCI/ASDU helper objects with initial counters.
sub_10001060 | EncodeApciHeader | 0x10001060 | Populate APCI control fields for I/S/U frames.
sub_100010F0 | DecodeApciHeader | 0x100010f0 | Extract APCI control values from raw bytes.
sub_10001330 | ParseAsdu | 0x10001330 | Decode IEC ASDU metadata & payload pointer bookkeeping.
sub_100013C0 | SerializeAsdu | 0x100013c0 | Assemble ASDU fields back into wire format.
sub_10001490 | ConsolePrintf | 0x10001490 | Variadic formatter to stdout or redirected file handle.
sub_10004E20 | InitializeSessionDefaults | 0x10004e20 | Seed session with defaults (log path, D2MultiCommService.exe, ports).
sub_10002130 | CopySessionRecord | 0x10002130 | Deep-copy 66 kB session structure, transfer vector ownership.
sub_10004830 | ReleaseSessionVectors | 0x10004830 | Free all vector-backed buffers in session array.
sub_10003A30 | DescribeWinsockError | 0x10003a30 | Map Winsock error codes to printable text.
sub_10003AC0 | DescribeCauseOfTransmission | 0x10003ac0 | Return human-readable IEC cause of transmission string.
sub_10003B80 | DescribeIecTypeId | 0x10003b80 | Resolve IEC type IDs to mnemonic strings.
Behavioral Analysis
- Config-Driven IEC-104 Orchestration
- LaunchConfiguredIec104Sessions:0x100014f9 loads the operator-supplied path, parses session definitions, and spawns one worker per 66 kB record via CreateThread (0x10001547) before joining with WaitForMultipleObjects (0x100015b9).
- ParseIec104ConfigFile consumes keyword/value pairs (target_ip 0x100017B0, target_port 0x10001804, sequence 0x10002004, uselog 0x10001AA5, socket_timeout 0x10001BAE, range 0x10001BF3, shift 0x10001F74) to populate IPs, ports, ASDU IDs, timing windows, operation sequences, and logging flags within each session record.
- Default initialisation (InitializeSessionDefaults:0x10004E20) primes every session with high-value defaults, including watchdog timers (dwMilliseconds = 1000 ms at 0x10021894) and a target service ("D2MultiCommService.exe" at 0x10004ED3), highlighting intended ICS victim context.
- IEC-104 Transport & Framing
- Workers establish network reachability through Iec104Connect (WSAStartup 0x100023E9, socket 0x10002499, connect 0x100024EB) and impose 15 s receive timeouts by writing dword_10021890 (15000) via setsockopt 0x10002543.
- APDUs are built with AllocateApduContext → EncodeApciHeader/SerializeAsdu and dispatched by TransmitApdu (send 0x10002642) while inbound traffic is collected by ReceiveApdu (recv loop 0x10002730) and decoded in ProcessIncomingApdus before logging through LogApduDetails (color-coded console output plus optional file append).
- Control hygiene is maintained with scheduled SendSupervisoryFrame and SendControlUFrame invocations (refs 0x10002993, 0x10003652) to emit STARTDT/STOPDT/TESTFR frames aligned with IEC-104 expectations.
- Programmable Command Sequences
- RunIec104SessionWorker compares the session mode string (strcmp(...,"sequence") at 0x100030E6) then iterates config-derived vectors (command_type, operation, range, shift accesses around 0x10003119–0x10003241) to drive stateful operations.
- Command execution funnels into IssueSingleCommand (calls at 0x1000331A/0x1000335E/0x100034E6/0x10003507), which hardcodes IEC type 45 (*(_BYTE *)=45 at 0x10002DB0) and programs qualifier bits (a4+48/50 usage) before transmitting and awaiting confirmation.
- Combined with ProcessIncomingApdus increments and range bounds, the toolkit can repeatedly actuate field devices, step through queued operations, and react to acknowledgements, enabling remote manipulation of substations or breakers.
- Local Service Disruption & Anti-Interference
- When stop_comm_service is enabled, workers call FindProcessIdByName and, upon success, execute OpenProcess/TerminateProcess (0x1000303D/0x10003046) against the configured service name (defaults to D2MultiCommService.exe), directly halting ICS communication software.
- Silent/verbose behaviour toggles (this[2] check in RunIec104SessionWorker and Iec104ClientThread) plus file logging (uselog, logfile) afford attackers operational flexibility while maintaining live feedback through LogApduDetails and printable IEC cause/type breakdowns.
- Execution Flow Summary
- Caller exports Crash to kick off, which parses configuration and spins up one worker thread per target.
- Each worker optionally disables a competing communication service, opens an IEC‑104 TCP session, performs the STARTDT handshake, and logs the negotiated counters.
- The worker walks the configured timeline (range/shift) of IEC operations, repeatedly issuing single commands or control frames, checking acknowledgements, and re-queueing as dictated by the script.
- Threads persist indefinitely, maintaining supervision frames and logging traffic until manually stopped.
Evidence Summary
- LaunchConfiguredIec104Sessions:0x100014f9–0x100015b9 ties configuration ingestion to multi-threaded execution against all parsed session blocks.
- ParseIec104ConfigFile token references (target_ip 0x100017B0, stop_comm_service 0x100018EF, command_type 0x10001DDF, operation 0x10001F1F, sequence 0x10002004) demonstrate attacker-controlled scripting parameters.
- Service-kill path in RunIec104SessionWorker (OpenProcess 0x1000303D / TerminateProcess 0x10003046) coupled with default target string D2MultiCommService.exe (0x10004ED3) evidences deliberate ICS disruption tooling.
- IEC transport stack: Iec104Connect (WSAStartup 0x100023E9, connect 0x100024EB) plus TransmitApdu (send 0x10002642) and ReceiveApdu (recv 0x10002730) confirm bespoke IEC‑104 client implementation.
- Command issuance via IssueSingleCommand:0x10002D30 (type ID 45 assignment at 0x10002DB0, qualifier handling 0x10002DE3–0x10002E05) and scheduling logic (range use at 0x1000315D, shift at 0x100031AE) highlights automated actuator control.
Verdict Malicious — purpose-built IEC‑104 intrusion tool capable of terminating industrial communication services and executing scripted control commands against substations; functionality, configuration surface, and targeted defaults provide clear adversarial intent.
Next Steps
- Locate and secure any companion configuration scripts on the affected host; they will disclose intended targets and command schedules.
- Isolate ICS assets reachable from the compromised machine, review IEC‑104 logs for matching command sequences, and coordinate with plant operators to validate system integrity.
@0x100014e0LaunchConfiguredIec104Sessions:0x100014f9CrashWSAStartup: Winsock network communication protocolDllMainCrashsymbol creates threadCreateThreadto execute at start addressStartAddressStartAddress: "IEC-104 client: ip=%s; port=%s; ASDU=%u"References