BeCtrl: policy lures, borrowed apps

About this post: Thanks to zhujiabao050624 for flagging this sample. This analysis and write-up were produced by Claude (Opus 5.5), working as an agent in Claude Code on a REMnux analysis VM. Tools used: Malcat, ILSpy (ilspycmd), capa, osslsigncode, tshark, Recorded Future Triage, ANY.RUN, Censys and VirusTotal.

TL;DR

This sample arrived as a ZIP named like a policy paper: Integrated_Assessment_Indo-Pacific_Economic_and_Security.zip. Inside is a "document" that is a validly signed PDF editor "PDFgear" and a hidden CommonLib.dll that the program loads automatically. The attackers rewrote that DLL from scratch. Every PDFgear function in it is an empty shell, except the one function the program calls first, which starts a small backdoor that calls itself BeCtrl.

  • It moves in quietly: both files are copied to C:\ProgramData\Microsoft\DeviceSync\, an old "Load" registry value starts them at logon, and the restart is disguised as a child of Explorer.
  • It phones home over port 53: it talks to 31[.]59[.]184[.]185 and 103[.]175[.]50[.]32, first over UDP port 53 (the DNS port, but not DNS), then over encrypted WebSockets on six other ports.
  • It does two things, and both are dangerous: the operator can run any program or command and push any file (up to 10 MiB) to any path.
  • The C2 was live: in two public Triage runs the server accepted the login and kept the session alive with heartbeats. No commands arrived while we watched.
An illustration, not a screenshot, with a made-up file name. Left: with Windows default settings, the victim sees one file that looks like a document. Right: with hidden files and extensions shown, it is a genuine app that loads a hidden, fake CommonLib.dll, and that DLL contacts the C2 server.
Image: An illustration, not a screenshot, with a made-up file name. Left: with Windows default settings, the victim sees one file that looks like a document. Right: with hidden files and extensions shown, it is a genuine app that loads a hidden, fake CommonLib.dll, and that DLL contacts the C2 server.

A real program with a fake library

Most programs don’t do all their work alone; they lean on libraries, DLL files that sit next to them and provide shared functions. PDFgear’s small helper RegExt.exe (it registers PDFgear as the PDF handler) relies on a library called CommonLib.dll. Windows, or in this case the .NET runtime, looks for that library in the program’s own folder first.

That lookup order is what the attackers exploit. If you put your own CommonLib.dll next to the real program, the real program will happily load it. This trick is usually called DLL sideloading.

Here the swap is unusually thorough. The fake DLL carries PDFgear’s name, version (2.1.18.0) and description, and it provides every function RegExt.exe expects, from AppIdHelper.IsAdmin to ShellHelper.UpdateFilePinState. All of them are empty and return nothing useful, except SqliteUtils.InitializeDatabase(), which is the very first thing RegExt.exe calls when it starts. That one function starts the backdoor.

Moving in

The first time the backdoor runs, it checks whether it is already in its preferred directory. If not, it:

  1. creates C:\ProgramData\Microsoft\DeviceSync\ (a folder name chosen to blend in with real Windows folders);
  2. copies the running program there as RegExt.exe and the DLL as CommonLib.dll;
  3. adds an autostart entry. For a normal user that is the old Load value under HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows, a legacy autostart spot that many people never check. When it runs as SYSTEM it uses the familiar Run key with the name PDFgear DeviceSync;
  4. restarts the copy and exits.

The restart uses a trick called parent PID spoofing. Every Windows process records which process started it, and security tools use that "family tree" to spot odd behaviour. BeCtrl asks Windows to record Explorer as the parent instead of itself, so the new process looks like something the user opened from the desktop. Triage flagged exactly this ("Suspicious use of NtCreateUserProcessOtherParentProcess").

A mock-up of the process tree an investigator would see: RegExt.exe appears as a child of explorer.exe, because the lure that really started it set Explorer as the recorded parent and then exited.
Image: A mock-up of the process tree an investigator would see: RegExt.exe appears as a child of explorer.exe, because the lure that really started it set Explorer as the recorded parent and then exited.

This relaunch only happens once. At the next logon, the autostart entry starts the DeviceSync copy directly; the backdoor sees that it is already in its directory, skips the install and goes straight to its server, so there is nothing to disguise. The spoofing comes back for every program the operator runs later: those are also launched with Explorer as their recorded parent instead of RegExt.exe.

A side effect is a useful clue for defenders. When the relocated RegExt.exe runs, the real PDFgear code inside it does its normal job and registers PDFgear as a PDF handler, pointing at C:\ProgramData\Microsoft\DeviceSync\PDFLauncher.exe. That file doesn’t exist. A PdfGear.App.1 registration pointing into DeviceSync is therefore a strong sign of this infection.

Phoning home: port 53 that isn’t DNS

The backdoor’s settings are stored lightly scrambled (each character XORed with the value 0x55), and decode to two server IPs plus a list of ports. It tries them in this order for each server:

  • UDP port 53 first. That is the DNS port, which many networks let through without a second look, but the data is not DNS. Every packet starts with the four letters PRO1, the backdoor’s own protocol marker.
  • then WebSocket over TLS (a long-lived, two-way connection that looks like web traffic) on ports 443, 80, 22, 21, 8080 and 1080. It accepts any certificate the server presents.

It stops at the first port where the login succeeds. If nothing answers on either server, it waits a little longer each time (1, 3, 5, 10, then 30 seconds) and starts again from the first server.

How BeCtrl looks for its server: every port on the first server in order, starting with UDP port 53, then the same on the second server, then a pause before starting again. The two IPs are the ones in this post's sample.
Image: How BeCtrl looks for its server: every port on the first server in order, starting with UDP port 53, then the same on the second server, then a pause before starting again. The two IPs are the ones in this post’s sample.

The first message is a login. The backdoor generates a fresh random key for the session and locks it with an RSA public key embedded in the DLL. Only the operator, who holds the matching private key, can unlock it; everything after that is encrypted with that session key (AES-256-GCM). The login carries the computer name, the Windows version, and a fingerprint built from the network card’s MAC address and the C: drive’s serial number.

Once logged in, the operator has just two features:

  • Run a command: by default BeCtrl runs cmd.exe /c <command>, but the operator can name a different program to start. The output goes to a randomly named .tmp, .dat or .log file in the Temp folder, is sent back in chunks, and the file is deleted.
  • Push a file: the operator can write any file of up to 10 MiB to any full path on the disk, with options to refuse, overwrite or rename if a file is already there.

That sounds minimal, but a remote command prompt plus a way to upload tools is all an intruder needs to look around, steal documents and bring in more capable malware.

What the sandboxes saw

Two public Triage runs (Windows 10 and Windows 11) reached the live server at 31[.]59[.]184[.]185 over UDP port 53. The packet headers of this protocol are not encrypted, so we can see each conversation’s shape even without the key: one login, one "login OK" with a session number, then a steady stream of heartbeats for the rest of the run. In neither session did the operator send a command or a file.

The ANY.RUN runs were less useful for traffic. An earlier public run shows the full install and the backdoor trying every server and port, but that run used simulated internet, so none of the requests reached the real servers. ANY.RUN does have a dedicated network rule for this backdoor ("BeCtrl PRO1 CnC handshake over UDP"), which fires on the login packet.

A wider campaign

Every copy of BeCtrl carries the operator’s RSA public key, the one that locks each session key. That key is a hard fingerprint: only someone holding the matching private key can use it. Searching VirusTotal for it found ten BeCtrl DLLs, including ours. All of them carry the same key and the same protocol code, so they belong to one operator.

They were not all hidden behind PDFgear. The operator used three different genuine, signed programs as hosts:

  • PDFgear’s RegExt.exe, version 2.1.16 in the earliest builds and 2.1.18 in later ones, with a fake CommonLib.dll;
  • Greenshot (a free screenshot tool), with a fake Greenshot.Base.dll;
  • Snoop (a free developer tool for inspecting Windows apps), with a fake Snoop.Core.dll.

The Greenshot and Snoop builds don’t wait for a particular function to be called. They use a .NET feature (a "module initializer") that runs their code the moment the DLL is loaded. Each build also uses its own folder, scheduled task or registry value to survive a reboot, so defenders should not rely on the DeviceSync path alone.

The original lure names are what tie the campaign together. Each one reads like a government or think-tank document from South or Southeast Asia. The table is sorted by the date each DLL was first uploaded to VirusTotal. An upload date only tells us the file existed by then, not when it was built or sent: the last PDFgear 2.1.16 build in the table, for example, uses the same servers as the July builds but was not uploaded until November.

First uploaded to VirusTotal Host program Original lure name and BeCtrl DLL (SHA-256) C2
2026-07-16 PDFgear 2.1.16 IPRD-2026_Invitation_Letter
d429ad9e8710bc1d5fd4f9354812784df3dadc81258f27847a218dce7277d422
139[.]84[.]169[.]184
103[.]175[.]50[.]32
2026-08-04 PDFgear 2.1.16 MOU USI-INDSR, TAIWAN
e026f584df835d58d73f8a05566213b157edb6db8858d067d1076ab457b1c4f2
139[.]84[.]169[.]184
103[.]175[.]50[.]32
2026-08-06 PDFgear 2.1.16 Nepal-India_Hydropower_Projects (program named Nepal-India_Hydropower_Cooperation_Proposal_2026.exe)
692e93fd1fc9922bfea801f8ece908e40c0e299f51e907b39114461dbd3ab66d
139[.]84[.]169[.]184
103[.]175[.]50[.]32
2026-09-16 PDFgear 2.1.18 MoU_USI_India_and_INDSR_Taiwan
486119e45dadf2b3bafd974e0ea5e1e8e8bc35be320649bfb03ceb12406e7dcd
139[.]84[.]169[.]184
103[.]175[.]50[.]32
2026-09-23 Snoop Internal_Protocol_Revised_Sept2026 (program named Internal_Protocol_Revised_Sept2026.docx.exe)
cdc31b7b51538f9eb766ee21ae25fd4de7197556ac0b8b49ad39aaaa62f5c7a8
5[.]253[.]28[.]160
2026-09-24 PDFgear 2.1.18 Thai Talking Points(PM) 14 00hrs(Final version) – PW
aa424e71f1c25d2455e14dadae35b380950dd4c73988183e7df88e1ed67e4d27
139[.]84[.]169[.]184
103[.]175[.]50[.]32
2026-10-12 PDFgear 2.1.18 Integrated_Assessment_Indo-Pacific_Economic_and_Security (this post’s sample)
4748571d98c6af34f4967a3886f73b4421239a1203f048140d3bfdaf8aa78937
31[.]59[.]184[.]185
103[.]175[.]50[.]32
2026-10-17 Greenshot MM_Gov_Secure_Portal_Ref_992_2026
e650a935e00bb51e2bcbf975a7bdfc0f03d18e9079e4bceaeff2c915d194231b
5[.]253[.]28[.]160
2026-11-03 Snoop unknown (DLL seen on its own)
04c729b5fd540e15952d8d9b954ea5616e9670821b914d0c063b453aface5386
5[.]253[.]28[.]160
2026-11-05 PDFgear 2.1.16 unknown (DLL seen on its own)
45095e850d54f5ccf0ca20527ec6f8aed6d5d8eaa3a002255cea06c87627dd48
139[.]84[.]169[.]184
103[.]175[.]50[.]32

"MM" in the Greenshot lure is the country code for Myanmar, which fits the UTC+06:30 timestamps in our ZIP. USI (the United Service Institution of India) and INDSR (Taiwan’s Institute for National Defense and Security Research) are real defence think tanks whose names the lures borrow.

Each BeCtrl build placed on the date it was first uploaded to VirusTotal, one row per host program. The marker shows which servers the build contacts: the switch to 31[.]59[.]184[.]185 appears only in October.
Image: Each BeCtrl build placed on the date it was first uploaded to VirusTotal, one row per host program. The marker shows which servers the build contacts: the switch to 31[.]59[.]184[.]185 appears only in October.

Timeline. The upload dates run from mid-July to early November 2026. PDFgear lures appear throughout; the Greenshot and Snoop builds appear from late September.

Server changes.

  • The earliest PDFgear builds use 139[.]84[.]169[.]184 and 103[.]175[.]50[.]32.
  • Our October build replaces 139[.]84[.]169[.]184 with 31[.]59[.]184[.]185 and keeps 103[.]175[.]50[.]32.
  • The Greenshot and Snoop builds use a different server, 5[.]253[.]28[.]160.

Sandbox runs. Public Triage runs of the older PDFgear builds and of the Greenshot build reached their servers and logged in. Each session shows the same pattern: a login, a "login OK", then heartbeats. As with our sample, no session contained a command or a file.

The servers behind it

Both servers in our sample are rented Windows machines, one in India and one in Malaysia. Besides the UDP channel, they run the backdoor’s WebSocket listener on TCP port 21 (and 443 on the second server). The listener uses a self-made TLS certificate with the unusual name QFC-Server.

We searched Censys for other servers presenting a QFC-Server certificate and found three more. Together with the server from the earliest builds, that makes six:

Server Hosting (location) How we linked it Status (mid-November 2026)
31[.]59[.]184[.]185 Ultahost (India) C2 in this sample online
103[.]175[.]50[.]32 GB Network (Malaysia) C2 in this sample and in the older PDFgear builds online
139[.]84[.]169[.]184 Vultr (India) C2 in the earliest PDFgear builds offline since late October 2026 (replaced by 31[.]59[.]184[.]185)
5[.]253[.]28[.]160 Netranex (India) Censys search; C2 in the Greenshot and Snoop builds online, listening on all six of the backdoor’s ports
135[.]136[.]8[.]254 M247 (Singapore) Censys search; same certificate as 5[.]253[.]28[.]160 online, lead only
103[.]215[.]216[.]157 G-Core (India) Censys search online, lead only

No sample we have connects to the last two servers, so we list them as leads, not as IOCs.

The certificates also show how the servers were set up:

  • July and August 2026: the first two certificates list private network addresses, such as 192.168.0.210, instead of a public server address. They were probably created on another machine and copied to the servers. One of them is installed on both 5[.]253[.]28[.]160 and 135[.]136[.]8[.]254, which is what links those two servers.
  • From September 2026: each new certificate lists the public IP address of the server it is installed on, so it was created on that server. The certificate on 103[.]215[.]216[.]157 follows the same pattern as the confirmed C2 servers.

Who is behind it?

We don’t know. The lures, documents about Indo-Pacific security, Myanmar government business, regional think tanks and Thai and Nepali policy, fit espionage-style targeting, and the ZIP’s timestamps were written on a computer set to UTC+06:30, Myanmar’s time zone. ANY.RUN labels the activity with a well-known China-nexus actor name, but its reasoning isn’t public. Nothing in the sample itself (servers, keys, code or build artefacts) connects it to previously documented activity we could verify, so we are not making that attribution. Code-similarity search (KesaKode) found no meaningful match to known families either.

What we couldn’t see

  • Commands: the sessions we could observe carried no tasking, so we don’t know what the operator does after a successful login.
  • Traffic contents: the session key is locked with the operator’s RSA key, so captured traffic can’t be decrypted. Only the unencrypted packet headers can be read.
  • Delivery: we don’t know how the ZIP reached its targets (email attachment, link, or something else).

Advice

For everyone: a "report" or "assessment" that turns out to be an .exe is never a document. If an archive opens to a program with a long, official-sounding name, stop there, even if Windows shows a valid signature.

For defenders:

  • Look for C:\ProgramData\Microsoft\DeviceSync\RegExt.exe / CommonLib.dll, a Load value under HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows, or a PDFgear DeviceSync Run value.
  • Hunt for a PdfGear.App.1 file association pointing into ProgramData\Microsoft\DeviceSync.
  • On the network, UDP port 53 to an IP that is not your resolver, with payloads starting PRO1, is this backdoor. A TLS server certificate named QFC-Server is its server side.
  • A signed vendor EXE running from a user folder or ProgramData, next to an unsigned DLL with the same company name, deserves a closer look.

IOCs

Type Indicator Notes
IP 31[.]59[.]184[.]185 C2 #1, UDP/53 "PRO1" and WSS 443/80/22/21/8080/1080
IP 103[.]175[.]50[.]32 C2 #2, same ports
TLS cert (SHA-256) 080cd3b79fa1eb7e523dab3d4edf4e703a33e8530233d99234a3b79d5cbc81aa CN=QFC-Server on C2 #1
TLS cert (SHA-256) 6e802cd13ece669a0467ad828b40076af760ee730636a973245722948cf6807e CN=QFC-Server on C2 #2
SHA256 4748571d98c6af34f4967a3886f73b4421239a1203f048140d3bfdaf8aa78937 CommonLib.dll (BeCtrl backdoor)
SHA256 d74fee10090cae17655d137e060398ce6fe52eb811ebc67a439ef37297e5014f Integrated_Assessment_Indo-Pacific_Economic_and_Security.zip
File name Integrated_Assessment_Indo-Pacific_Economic_and_Security.exe lure name for the genuine signed PDFgear RegExt.exe (no hash: legitimate file)
Path C:\ProgramData\Microsoft\DeviceSync\CommonLib.dll persisted backdoor
Path C:\ProgramData\Microsoft\DeviceSync\RegExt.exe persisted host (genuine PDFgear file)
Registry HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\Load autostart (user)
Registry HKLM\Software\Microsoft\Windows\CurrentVersion\Run\PDFgear DeviceSync autostart (SYSTEM)
Mutex Local\PDFgear_DeviceSync_Mutex, Global\PDFgear_DeviceSync_Mutex single instance
Network pattern UDP payload starting 50 52 4F 31 01 ("PRO1") BeCtrl frame header
IP 139[.]84[.]169[.]184 C2, earlier PDFgear builds
IP 5[.]253[.]28[.]160 C2, Greenshot and Snoop builds
SHA256 d429ad9e8710bc1d5fd4f9354812784df3dadc81258f27847a218dce7277d422 CommonLib.dll (PDFgear 2.1.16 build)
SHA256 e026f584df835d58d73f8a05566213b157edb6db8858d067d1076ab457b1c4f2 CommonLib.dll (PDFgear 2.1.16 build)
SHA256 692e93fd1fc9922bfea801f8ece908e40c0e299f51e907b39114461dbd3ab66d CommonLib.dll (PDFgear 2.1.16 build)
SHA256 45095e850d54f5ccf0ca20527ec6f8aed6d5d8eaa3a002255cea06c87627dd48 CommonLib.dll (PDFgear 2.1.16 build)
SHA256 486119e45dadf2b3bafd974e0ea5e1e8e8bc35be320649bfb03ceb12406e7dcd CommonLib.dll (PDFgear 2.1.18 build)
SHA256 aa424e71f1c25d2455e14dadae35b380950dd4c73988183e7df88e1ed67e4d27 CommonLib.dll (PDFgear 2.1.18 build)
SHA256 e650a935e00bb51e2bcbf975a7bdfc0f03d18e9079e4bceaeff2c915d194231b Greenshot.Base.dll (BeCtrl)
SHA256 cdc31b7b51538f9eb766ee21ae25fd4de7197556ac0b8b49ad39aaaa62f5c7a8 Snoop.Core.dll (BeCtrl)
SHA256 04c729b5fd540e15952d8d9b954ea5616e9670821b914d0c063b453aface5386 Snoop.Core.dll (BeCtrl)
SHA256 a2b65ea2e827637890d55cf681705ea4639f75fae1a185b05b8425ae6d05a617 IPRD-2026_Invitation_Letter archive
SHA256 7ecac9d9d59a43e710a67f8377f40d5c1f50e113dc302db0f0fe377fd0558a52 MOU USI-INDSR, TAIWAN archive
SHA256 11908bbfdea5e8d9f87fbe045816fff927d17f32b6e89e17ad2be27a57579ff8 Nepal-India_Hydropower_Projects archive
SHA256 8507d593880dfeb8b56ca8caceb72887bcb8cd7455891e89be3860bf4d2d5e16 MoU_USI_India_and_INDSR_Taiwan archive
SHA256 b542e171c8da17958538d5e5a2b10d2fdc0e2c049d12f7f339d5e723b1238949 Thai Talking Points(PM) 14 00hrs(Final version) – PW archive
SHA256 94275fed254303780d9034c0e6a380db59221b6f13a897bf2a9e49e0fa3b0e64 second archive carrying this post’s CommonLib.dll
SHA256 6ed06f2e552f1e42643acf2014dcca678638a3c665d75891c70770f6f4278563 MM_Gov_Secure_Portal_Ref_992_2026 archive
SHA256 e3b3599d9efcaea3fd2c4835c31144b883b4858a9d17d8c1b3bd9a65e31181c5 MM_Gov_Secure_Portal_Ref_992_2026.rar
SHA256 d02492ac26c886235ecc6792b630787559f09116e19373edb3021687d5be012e Internal_Protocol_Revised_Sept2026 archive
Path %LOCALAPPDATA%\RegExt\, %LOCALAPPDATA%\PDFgear\Services\ older PDFgear builds
Path %LOCALAPPDATA%\GreenshotTileCache\, %LOCALAPPDATA%\WpfVisualTreeHelper\ Greenshot / Snoop builds
Scheduled task RegExtRegistrationTask, GreenshotTileCacheTask, SnoopVisualTreeTask persistence, sibling builds
Registry HKCU\Software\Microsoft\Windows\CurrentVersion\Run\PDFgear FileSync autostart, PDFgear 2.1.18 build
Mutex Local\PDFgear_ConfigSync_Instance, Global\{2ad2e55f-3b2b-4223-ae1a-4e552ceeb7c9}, Global\{e9d1bf88-8b81-4486-a69d-517edd7b795e} single instance, sibling builds
Public key RSA SPKI SHA-256 544babf3c6485418c35f8db11f1110e70e06af78f690d556beec1d6008eb1df6 operator key embedded in every BeCtrl build

Closing

BeCtrl itself is small: it can run commands and upload files, and nothing more. What makes it work is the delivery. A familiar program loads a fake library from its own folder, and each lure is named for the people expected to open it. Across ten builds and at least four months, the operator changed host programs, folders and servers, but kept the same RSA key and the same PRO1 protocol. Those two things are the most reliable way to find new builds. If you have seen BeCtrl or the PRO1 protocol elsewhere, we would love to compare notes.

Sandbox runs: Triage 261111-sdc5fsg15r · ANY.RUN b4c1b80f