When I chased a proxy pool’s own torrents down to a cracked driving game, there was a second thread in that post I gave four paragraphs and then walked past. Under an installer that just asks I wrote that the pool’s exits kept leaving the footprint of one particular consumer torrent client, that I’d put it on a throwaway VM, and that its setup offered two commercial bandwidth-sharing SDKs as opt-in add-ons. Then I went back to the interesting encrypted payload in the APK and left it there.

That was the lazy half of the post, and it’s been bothering me since. The APK thread ends in an honest shrug — a packed payload I still can’t prove is proxyware. This one doesn’t have to. There’s no packer, no encryption, nothing to decrypt: it’s a signed installer that will tell you exactly what it does if you ask it properly.

So this is that paragraph, finished. The client is MediaGet. 3.2 MB, PE32, signed. And the “two bandwidth-sharing SDKs” I saw on the VM turned out to be two of eleven.

The URL isn’t in the file

First move is always the same: pull strings, look for where it phones home. What came out was almost nothing. Some libcurl scaffolding, some OpenSSL, DigiCert CRL URLs, one lonely http://mediaget.com, and Google’s own Web Store install endpoint — which pairs with an extension_id field in the config schema and is a whole second delivery channel I’m not chasing here. No payload URLs. No vendor names. Nothing that looked like a bundle.

What was in there was the shape of a bundling engine:

<bundles_list>
Unable to download bundle :
Unable to run bundle
Bundle service name empty
Bundle service not started
&bundlesInstalled=

Plus an RTTI type descriptor, .?AVBundleController@Bundles@@class Bundles::BundleController — and, the tell that mattered, an import table containing OpenSCManagerW, OpenServiceW, QueryServiceStatusEx and StartServiceW, with no CreateServiceW anywhere. Open, poll, start, wait. Nothing that registers a service. That’s precisely the shape you need if your job is to run a third party’s installer and then bring up whatever daemon it just registered.

So the installer is a stub. The interesting part is downloaded, which means the interesting part is on a server, and I needed to find out which one.

Three path fragments were sitting in .rdata, next to each other and next to the bare host:

https://
http://
mediaget.com
/client/installer.php
/ld/get_bconfig.php
/ld/get_data.php?id=

Adjacency in a string pool is suggestive, not proof — a compiler can put unrelated literals side by side. So I disassembled and followed the cross-references. Two cached-static getters for the pieces, and three more functions that assemble URLs the same way: call the host getter, call the scheme getter, concatenate, append their own path.

sub_5b0e2c()  → "mediaget.com"                  (host getter)
sub_5b10d7()  → "https://" | "http://"          (scheme getter, downgrades on a flag)
sub_5b0ea4()  → scheme + host + "/ld/get_bconfig.php"
sub_5b0f43()  → scheme + host + "/ld/get_data.php?id=" + <installId>
sub_5b1038()  → scheme + host + "/client/installer.php"

All five are MSVC thread-safe function-local statics, so each string is built once and cached. Addresses are at the preferred image base 0x400000; the binary is ASLR-enabled, so rebase accordingly.

And a fourth builder at sub_5b7c3a, which calls the get_data one and then appends the query string a parameter at a time, in this order: &alreadyInstalled=, &vi=, &browsersInstalled=, &defaultBrowser=, &bundlesInstalled=, &installerVersion=, &os=, &isOs64bit=.

That list is the part worth pausing on. The installer tells the server what OS you run, whether you’re 64-bit, which browsers you have, which one is your default, and what it has already installed on you. Then the server decides what you get. The targeting logic isn’t in the binary at all — it’s server-side, which is exactly why the binary looks so clean.

Asking the server

/ld/get_bconfig.php returned a flat HTTP 500 to everything I threw at it. /client/installer.php was more talkative — it answered <Error>Not correct XML</Error>, which tells you it’s the telemetry sink and wants a document, not a query.

/ld/get_data.php?id=0 just worked.

<parameters>
  <country>ua</country>
  <reseller>ms_google</reseller>
  <bundles_list>
    <opera></opera>
    <antivirus360></antivirus360>
    <mgru></mgru>
  </bundles_list>
</parameters>

It geolocated me — ua, correct — and handed back three offers. Opera, 360 Total Security, and something called mgru.

Each entry in that list is a full install recipe, and the field names give the game away:

url / urls              command_line            exe_name
need_admin              add_to_firewall         add_to_autorun
conflicting_bundles     install_order           close_browsers
name_installed_service  run_installed_service   wait_service_secs
after_install_check_process

name_installed_service, run_installed_service, wait_service_secs — there it is. The schema has first-class support for “install this thing, then bring up the service it registered and wait for it.” That’s the StartServiceW import from earlier, and it’s not a shape you need for a browser offer.

Ninety-six countries

If the offer set is chosen server-side and the response carries a <country> field, the obvious next move is to ask from somewhere else. I ran the same request through residential exits in 96 countries and diffed the results. Ninety-three came back with a usable <bundles_list>; three returned nothing, which I read as a routing failure at my end rather than a finding.

The offers rotate by geography, cleanly:

Where you areWhat you’re offered
GB DE NL BE AT CZ HU DK SE PT LT CA AU ES IT PH HK SGinfatica
PL JP KR TW LV AZ KZ UZsoax
UA RU BY TR, most of LatAm, Africa, Middle Eastmgru

Two named residential-proxy networks — Infatica and SOAX — served across Europe, the Anglosphere and parts of Asia, and neither of them was offered to Ukraine, Russia, Belarus or Turkey.

Most proxy bundles carried the same line:

<conflicting_bundles>bdvpn</conflicting_bundles>

Strictly that only rules out co-installing alongside the Bright Data VPN offer — one slot per host is what I observed across the sweep, not something the schema guarantees. And it isn’t set uniformly: the mgru entry served to Ukraine comes back with <conflicting_bundles/> empty, while opera in the very same response populates it with yabrowser,coccoc. The field works fine. The operator just doesn’t set it there.

I still hadn’t found the two offers I’d actually seen on the VM. Neither proxysdk nor neunative came back from a single exit in the sweep — whatever was in rotation when I first watched this thing install was not in rotation now. What I had instead was proof that the rotation exists, and that I was only ever seeing one slice of it at a time.

The installer’s own UI gives up the roster

The config response has a field I’d skipped: <html_url>. MediaGet doesn’t ship its installer UI in the binary — it downloads it, as a 7-Zip archive of HTML templates, images and strings.

Seventy-seven files. And bundles/ is the whole catalogue, whether or not any given entry is currently in rotation. Filtered to the proxy and bandwidth-sharing offers:

bundle-anyip.html      bundle-bdvpn.html        bundle-castar.html
bundle-earnapp.html    bundle-fluke.html        bundle-fluke-start.html
bundle-infatica.html   bundle-ipgate.html       bundle-luminati-wait.html
bundle-neunative.html  bundle-packet.html       bundle-proxysdk.html
bundle-repocket.html   bundle-soax.html

The rest are the ordinary offers — Opera, Opera GX, 360, Cốc Cốc, Adaware Web Companion, Yandex, a media player, a search hijack called YourSearch.

And then translations.json, which maps the proxy keys to brands — in the operator’s own words:

page.proxy_text.soax.en       = SOAX.COM
page.proxy_text.infatica.en   = infatica.io
page.proxy_text.ipgate.en     = IPGATE.IO
page.proxy_text.fluke.en      = flukeproxy.com
page.proxy_text.anyip.en      = anyip.io
page.proxy_text.repocket.en   = repocket.com
page.proxy_text.packet.en     = packet.com
page.proxy_text.castar.en     = castar.com
page.proxy_text.proxysdk.en   = proxy-sdk.com
page.proxy_text.neunative.en  = netnut.io

That’s ten brands. bdvpn makes eleven — Bright Data’s page sells a VPN rather than a proxy, so it gets no page.proxy_text entry, and earnapp and luminati are the same company again, so they don’t add to the count.

neunative is NetNut, and MediaGet’s files say so twice: that brand line, and bundle-neunative.html linking the offer’s EULA to netnut.io/terms-of-service. Both are strings MediaGet wrote — the payload itself carries no NetNut marking at all. Which is the other half of the point: it’s a key you’d never reach by grepping for “netnut”.

Templates go stale, though, so I wanted a second witness, and MediaGet ships one. Its own uninstaller hardcodes the directories it knows how to clean up:

\anyip-m    \flukeproxy   \IPgate       \neunative-m   \packet-m
\proxy-sdk  \repocket-m   \soax-m       \highsocks     \Infatica-m
\Luminati-m \mgru         \emproxy-service   \gsproxy-service

Nobody writes removal code for a bundle that never shipped. And two of those — emproxy-service, gsproxy-service — aren’t in translations.json at all, so the catalogue in the UI package isn’t even the full history.

The offer copy is worth reading, because it’s the honest part:

You will get an ad-free version of MediaGet in exchange for safely using some of your device’s resources (WiFi), and only in a manner that will not substantially affect the device’s operation. You may turn this off from the settings menu.

That’s one string, page.proxy_text.main, dropped verbatim into every branded proxy page. The only thing that changes between vendors is the brand line under the diagram and the two EULA links.

And it links the vendor’s own terms on the vendor’s own domain — netnut.io, soax.com, infatica.io, and so on. It’s disclosed.

It’s also, on this page, not a checkbox you can see:

<input type='checkbox' id='proxysdk_installCheck' checked='checked' style='display:none'/>

Pre-checked and display:none. Nothing on screen shows you a box, ticked or otherwise; your answer is decided entirely by which button you press, and only the skip handler ever sets it false. The continue button is 460 pixels wide and rgb(68,203,68) green. The skip button is 178 pixels wide, rgb(230,230,230) grey, with rgb(200,200,200) text on it — grey on grey. I pulled those numbers out of the HTML, they’re not an impression, and the same hidden checkbox and geometry repeat across the anyip, castar, fluke, infatica, ipgate, neunative, packet and repocket pages. SOAX is the exception: a visible radio pair, pre-selected to yes.

Finding the NetNut binary

Knowing the bundle key was neunative made the rest fall out. The hosted binaries follow a loose naming convention — <key>_setup_<seq>[_<variant>]_<date>[_<rev>].exe — and the Wayback Machine had crawled exactly one of them:

https://mediaget.com/installer/binaries/neunative_setup_2_2025-06-17.exe

Still live. 2.1 MB, Inno Setup, and inside it:

%LOCALAPPDATA%\neunative-m\neunative-m.exe   190 KB
%LOCALAPPDATA%\neunative-m\neunative.dll     1.1 MB

The DLL is where the network lives. Three domains sitting adjacent in the string pool, with a _uuid key wedged between them and a UUID regex immediately after, next to UuidCreate:

sky-borders.com
net-echo.com
tera-home.com

Adjacency isn’t proof of an array, so read that as a candidate endpoint set plus a persisted per-host identifier rather than a confirmed rotation list. What is unambiguous is how they get used: the SDK builds its URL from the literal https://lb. plus one of the three names, and requests /initreq?os=…&ver=…&model=…&manufactor=… with User-Agent: SDK. All three lb. hosts resolve to 64.62.203.99. One box, three names.

There’s also a pair of Google Drive URLs in there as a fallback config channel, both dead by the time I looked, which is a nice reminder that dead-drop resolvers are a maintenance burden nobody wants.

Update: this one got taken down

In the first week of July 2026 — after I pulled this sample, before I published — Google, the FBI and Lumen disrupted NetNut . Google’s account puts the network at more than two million devices and reports that in a single week of June 2026 its threat group observed 316 distinct threat clusters using suspected NetNut exit nodes — password spraying, accessing victim environments behind a laundered origin IP, and seeding Mirai variants. Google disabled the accounts NetNut used for command and control; the FBI seized domains.

I checked my own indicators on 25 July. All three domains still resolve to 64.62.203.99, and nothing answers on 443, 80, 8080 or 8443 — verified from three vantage points, so it is the service being down rather than my address being filtered. I had already reimplemented the /initreq call byte-for-byte and had nothing to point it at.

Two things worth drawing out. Google describes the recruitment mechanism as SDKs distributed inside applications — “users unknowingly download applications containing hidden proxy code” — and frames it around smart TVs, streaming boxes and Android. What is in this post is the Windows desktop arm of that same channel, documented from the bundler’s side: which torrent client shipped it, to which countries, behind which consent page, signed with whose certificate. And the thing worth sitting with is that this was the branded offer — the one with a working EULA link to netnut.io.

The part I got wrong

I’d written off mgru early. It’s served to Ukraine, Russia, Belarus, Turkey and most of the global south — the geos with no named proxy vendor — and the name reads like “MediaGet RU”. An updater. A regional build. Boring.

It is not an updater.

SdkRuntimeCoordinator timer tick.
Sending pulses to all link servers. Current pulse count: {}
Link server count is zero. Acquiring route node info.
Link server {}:{} connected.
Pulse sent to {}:{}.
TcpTunnelPipeline initialized. Key: {}. Active tunnel count: {}
TcpTunnelPipeline destroyed. Key: {}. Active tunnel count: {}
TunnelLinkGuardBase does not exist. Skip.
[CFG] Current endpoint: custom endpoint
[NET] Client IP: {}

Those are individual literals — the fragments get concatenated at runtime, so don’t grep for an assembled sentence. TcpTunnelPipeline, TunnelTcpLinkGuard and TunnelLinkGuardBase also surface as MSVC RTTI names, which is the part that survives someone stripping the logging. It’s a residential-proxy exit runtime: C++, Boost.Asio over SSL, link servers, tunnel pipelines, keepalive pulses, a device key. It talks to titan481iga.com, parked behind Cloudflare.

My first read was that this must be MediaGet’s own in-house relay — cut out the middleman in the regions where a name-brand vendor’s per-install rate doesn’t clear. That was wrong, and the binary says so plainly.

mgru.exe is Authenticode-signed by Giant Axe Technology Co., Limited (Kwun Tong, Hong Kong, company no. 77383001) — not by the Global Microtrading certificate on the dropper wrapped around it. Every Boost include path compiled into it is rooted at H:\lingjiang_git\pc_xingchen\sdk_all\app\castar_sdk\. It contains not one occurrence of the string “mediaget”, and its internal name is mgru_sdk.exe. castar is one of the ten branded keys in translations.json, and there’s an older MediaGet lib archive on the same server called lib_2025-12-15_uninst_castar_packet.

So mgru is another vendor’s SDK — a Castar build. The vendor list doesn’t get shorter in Ukraine. The label just comes off.

And Castar has a name in the literature. In January 2026, Google’s threat group, Spur, Lumen’s Black Lotus Labs and Cloudflare disrupted the IPIDEA network , of which CastarSDK is one of four interchangeable SDKs — Castar, Earn, Hex and Packet, all run by the same operator through Hong Kong entities, and, in their words, “exactly the same.” The exits are retailed under thirteen consumer brands: 360 Proxy, 922 Proxy, ABC Proxy, Cherry Proxy, Door VPN, Galleon VPN, IP 2 World, Ipidea, Luna Proxy, PIA S5 Proxy, PY Proxy, Radish VPN and Tab Proxy. That is why castar.com in MediaGet’s own brand table is a parked page: Castar is the name on the SDK, not on the shop.

I reverse-engineered this SDK before reading any of that, which makes three details load-bearing rather than decorative.

Google describes the operator’s second-tier servers as being “sent as connect and proxy pairs.” That is verbatim the shape of the route response I pulled out of the binary:

"node":[{"connect":"43.173.113.122:143","proxy":"43.173.113.122:222"}]

MediaGet’s own file server carries an archive named lib_2025-12-15_uninst_castar_packet.7z — one uninstaller covering castar and packet together. The bundler filed two of Google’s four SDKs as a single vendor, which is what they are.

And the consent gap lines up. Google found that the applications carrying these SDKs “did not disclose that they enrolled devices into the IPIDEA proxy network.” What I found, from the other end of the chain, is that mgru is the only bundle in MediaGet’s catalogue whose consent page is named in the config and absent from the package. Same concealment, documented from the distributor’s side.

The network also outlived the takedown. We are looking at it in July, six months on; titan481iga.com appears in none of the tier-one domains Google published, so this is rebuilt infrastructure. The scale in that report explains something I had wondered about — I could only ever find about nineteen distinct nodes at a time, and their shared second-tier pool held roughly 7,400 servers. I was sampling a sliver. In one week of January, they counted over 550 distinct threat groups using its exits.

And that’s the finding, sharper than the one I thought I had. Every geo that answered me got a proxy slot. Across the ninety-three that returned a bundles_list, I never saw one come back without a proxy bundle in it. What changes is the disclosure. Every branded vendor has a bundle-<key>.html consent page in the UI package. mgru doesn’t, and not by omission: its config entry sets <html_page>mgru.html</html_page>, and mgru.html exists nowhere in the archive the installer actually fetches — 77 files, zero occurrences of the string “mgru”. The page is named and then not shipped. The installer’s own bundle parser also has a field called, with no ceremony at all, no_offer.

The consent screen is geo-fenced along exactly the same line as the brand. Western Europe gets Infatica and a EULA link. Ukraine gets a relay and a checkbox it never sees.

(Caveat on my own evidence: the UI package I pulled is dated 2026-05-04 and the mgru dropper is 2026-06-09, so I can’t rule out a newer package with a page in it. What I can say is that in the package the installer was actually fetching, there is none.)

Which closes the loop on the question the earlier post opened with: where do the exit nodes actually come from? There, I could only show that swarm peers and pool exits matched ISP-for-ISP and sometimes down to the same /24 — strong, but still two datasets agreeing about a population. Here the mechanism is in one file. A MediaGet install is a DHT peer, and in every geo that answered it is also handed a proxy exit — same installer, same session, one flow.

It also narrows a hedge I made last time. I’d written off the swarm/pool overlap as possibly nothing more than “a behavioral fingerprint of the crowd” — the people who pirate are the same people who install sketchy free software, and that correlation exists with or without malware. That’s still the right reading of the APK side of it, which MediaGet doesn’t touch. What MediaGet explains is the other signal: the torrent-client footprint the exits kept leaving. That one isn’t a coincidence of taste, because here the sketchy free software and the torrent client are the same program. What I still can’t show is that the particular pool I sampled buys from any of these vendors — that’s what would close it properly.

One certificate, and three ways of packaging

The pivot that makes this tractable for anyone else: every proxy dropper in the chain is signed by the same certificate as MediaGet itself. Not merely the same subject — the same leaf.

Subject:  C=SG, L=Singapore, O=Global Microtrading PTE. LTD, CN=Global Microtrading PTE. LTD
Issuer:   C=US, O=DigiCert, Inc., CN=DigiCert Trusted G4 Code Signing RSA4096 SHA384 2021 CA1
Serial:   04F27CB51D02E6B6F022B5F23EEA6886
Valid:    2023-09-15 → 2026-09-04

The non-proxy offers coming down the same pipe are not: the 360 Total Security dropper is signed by Beijing Qihu, the Opera droppers by Opera Norway AS, the Yandex one by YANDEX LLC through GlobalSign. Only the proxy wrappers get repackaged under MediaGet’s own subject, and that asymmetry is itself the tell.

Open the wrappers and the packaging model resolves into layers, which cuts three ways:

  • MediaGet-built controller plus vendor SDK. neunative-m.exe and highsocks.exe both carry C:\mediaget\mediaget-mini-installer\bundles-installers\<vendor>-controller\Release\…pdb build paths and MediaGet’s signature, shipped next to the vendor’s unsigned payload (neunative.dll, libmgmtkd_386.dll).
  • Vendor-signed, passed through untouched. infatica-service-app.exe is signed by O=Infatica Pte. Ltd. on a Sectigo cert — the one place in the whole sample set where a payload is provably the named vendor’s own build.
  • A third company entirely. mgru.exe, signed by Giant Axe Technology.

So the Singapore certificate enumerates the wrappers, not the payloads. Worth knowing before you build a hunt on it.

One more thing I’m not going to guess at: the binary’s own registry paths say Software\Media Get LLC\MediaGet2, and the certificate says Global Microtrading PTE. LTD, Singapore. Both strings sit in the same block of .rdata, a hundred bytes apart. I don’t know what the relationship between those two names is. The signing subject is the one that follows the droppers around, so it’s the one to pivot on.

Who’s actually behind the counter

proxy-sdk.com — the proxysdk bundle — links its EULA to proxy-sdk.com/agreement.html, and that page names Datacollect Limited, UK company number 15907323, Watford, as the party behind the service. That’s the site’s own statement about itself, read 25 July 2026 and checkable at Companies House; nothing in the sample set names Datacollect. MediaGet ships proxysdk and neunative as separate offers with separate consent pages and separate EULA links, so the bundler treats them as different vendors — I’d assumed at first they were the same thing.

The rest are established commercial networks with public storefronts, and the uncomfortable part is worth saying plainly: for the branded bundles, the installation is disclosed. There’s a consent page, it names the vendor, the terms link goes to that vendor’s own domain. On MediaGet’s side of the transaction, that is not what a botnet looks like.

Three caveats stay attached to that sentence, and the last one arrived while I was writing.

The disclosure isn’t universal — the slot served to Ukraine, Russia, Belarus, Turkey and most of the global south has no consent page in the package I pulled. I didn’t run any of these SDKs either; I can describe what they’re built to do from their strings, not certify that’s all they do.

And a disclosed install screen says nothing about what the pool does downstream. One of the eleven — NetNut, the one with the working EULA link — was disrupted by Google and the FBI in early July as a two-million-device network whose exits served 316 distinct threat clusters in a single week. Consent at the point of install and a botnet at the point of use are not mutually exclusive, and this chain produced both from the same green button.

What there is, then, is a torrent client that has built a country-by-country rotation of proxy bundles and labelled them with eleven brands. I want to be exact about who I actually caught doing what. Infatica and SOAX I watched being served, live, to real countries — and the Infatica payload is signed by Infatica. NetNut I pulled a live dropper for. The other eight I have from MediaGet’s own template pack and its own uninstaller: good evidence that the integration was built and shipped, and no evidence at all about what any vendor knew, was told, or was paid. There is no vendor-side document in this evidence set, and the wrappers carry MediaGet’s certificate rather than theirs.

Which leaves an open question pointed at the vendors rather than at me: if your SDK is being distributed through this channel, do you know?

If you buy residential proxies, some fraction of what you’re routing through is this. Somebody who wanted a torrent client, clicked a green button four times the width of the grey one, and is now a line item.

Indicators

Config endpoints:

https://mediaget.com/ld/get_data.php?id=<installId>&alreadyInstalled=&vi=
    &browsersInstalled=&defaultBrowser=&bundlesInstalled=
    &installerVersion=&os=&isOs64bit=
https://mediaget.com/ld/get_bconfig.php                        (HTTP 500 to every probe)
https://mediaget.com/client/installer.php                      (telemetry, wants XML)
https://mediaget.com/client/client2.php                        (second sink, hardcoded in highsocks.exe)
https://mediaget.com/installer/binaries/<bundle>_setup_<seq>[_<variant>]_<date>[_<rev>].exe
https://mediaget.com/installer/binaries/html_en_fix_<date>.7z  (<html_url>, the UI package)

Delivery has a fallback leg — the <urls> list carries a Selectel object-storage mirror:

https://21c37a1e-ae78-4a63-a3ba-a8a8fc9891db.selstorage.ru/<dropper>.exe

SDK network indicators:

BundleBrandEndpointA record
neunativenetnut.iolb.sky-borders.com, lb.net-echo.com, lb.tera-home.com/initreq, User-Agent: SDK64.62.203.99 — resolving but dead since the July takedown
infaticainfatica.io102.apiserv.org185.223.94.19
mgruCastarSDK (IPIDEA network)titan481iga.comCloudflare-fronted — origin not recovered, don’t blocklist the edge IPs. Tier-two nodes seen in 43.130–43.173.x and 170.106.x (Tencent Cloud SG)
soaxSOAX.COMno endpoint recoverable statically — see below

64.62.203.99 is Hurricane Electric, 64.62.128.0/17.

Two negative results worth stating, because I nearly published both as indicators. repo.king-support.com appears in the Infatica payload 355 times — every occurrence a Go module or import path, right down to the buildinfo record. It tells you where the source lives, not where the traffic goes. And the SOAX controller has no callback host in it at all: every domain-shaped string I first pulled out of highsocks.exe turned out to be a certificate authority’s display name from an embedded Mozilla root store, 138 certs of it. The vendor SDK is the unsigned 12.6 MB libmgmtkd_386.dll, a stripped Go build that resolves its servers at runtime and leaves no plaintext host behind.

Host and build artifacts, more durable than any address above:

Google Analytics  UA-156575473-1   (event category soax_sdk)
Autorun           Software\Microsoft\Windows\CurrentVersion\Run   value: highsocks
Registry          Software\Media Get LLC\MediaGet2\application
Build paths       C:\mediaget\mediaget-mini-installer\bundles-installers\soax-controller\Release\
                  C:\mediaget\mediaget-mini-installer\bundles-installers\neunative-controller\x64\Release\
                  H:\lingjiang_git\pc_xingchen\sdk_all\app\castar_sdk\        (mgru)

Droppers (SHA-256), all Global Microtrading-signed:

23c485023d4a37a870b27f6eedf4c5bb925a8b54338a994f9e57c3268c8f645e  neunative_setup_2_2025-06-17.exe
9f6912a9111c3740ac62d50d868124677da72c40a202a2bdd7ee81e570962d09  infatica_setup_8_win7_2025-01-29.exe
1c9cfe747fa72f25bf872b6862143acc2427c2b73e5535bfbcda2c2d48be8ca9  highsocks_setup_16_2026-07-17.exe
0b9ff25a3436aefb01903a803d140217c3c1ec1408984864246b15de1aeb9623  mgru_setup_1_2026-06-09_3.exe
1ca62a560ee6885b9c9187ade5c8933ec28a52323ffbc39f8e2ba9c9fb151247  MediaGet.exe

Payloads, all under %LOCALAPPDATA%:

6f072380a22e49e878caa0428db57682c50ffdbb8c2fd0108f079b0f1d353c5e  neunative-m\neunative-m.exe
21e005b83be7d27c4748bd65d21430aefdd7ee0032a3aba9a1005624fc8b450a  neunative-m\neunative.dll
939227fb2c6d159068d2c55cc0ede5c7f9e8a0d08bf581627aa6fdc02b173e93  Infatica-m\infatica-service-app.exe
d8d1bf78c88874653c36362d4cac0fa9ebbe29f0de5b28ad9d7c04e0e80f87cf  highsocks\highsocks.exe
c3237b50387c7be5ee34f8ae0cadb595093bba9bf9e055819c2480fb38150259  highsocks\libmgmtkd_386.dll
9abfebf172eb031e8b3dcab8fd4be45bac3511dc5c2486d397ac295af8a2ac68  mgru\mgru.exe

Host-side, the family drops to %LOCALAPPDATA%\<bundle-name>\neunative-m\, Infatica-m\, highsocks\, mgru\. The schema supports service registration, but none of the four payloads I pulled actually uses it: those fields come back empty in the live config, no payload imports CreateServiceW, and highsocks.exe persists through an autorun value instead. So the cheap check is a signed executable under %LOCALAPPDATA%\ with an unsigned DLL next to it, plus autorun entries pointing into %LOCALAPPDATA%.

A caveat about all of this

Everything above is one snapshot, taken on 25 July 2026 from one set of exits. The rotation moves. proxysdk and neunative were both being offered when I first watched this installer run in a VM, and neither was in rotation anywhere by the time I ran the sweep a few days later — I got the NetNut URL out of a web archive, not out of a live response. Anyone repeating this will get a different table.

That’s not a flaw in the method, it’s the finding. The binary is stable and boring and passes review. The behaviour lives on a server, changes weekly, and is different for every country it answers. Static analysis of the installer tells you almost nothing — you have to ask the server, and you have to ask it from enough places to see the shape.

Which leaves the other half of the original post still open. The cracked game’s encrypted payload is still sitting on the bench, still silent, still unproven. This one turned out to be the easy sibling: the disclosed channel, the one that files paperwork in Watford and signs its droppers. The hidden channel is the harder problem, and it’s the one I still owe an answer on.

Method note: everything here is the installer’s own config endpoint answering an unauthenticated GET, plus static analysis of binaries it handed me. No host was touched that didn’t offer the file. The geo sweep is one read-only request per country through a commercial residential network. Hashes and URLs are published because these are commercially signed, publicly downloadable adware installers rather than exploits — and because the whole point is that you can rerun the sweep and get a different table.