Article

    Cyber News / Article / Analysis of FvncBot campaign

    Analysis of FvncBot campaign
    Ka
    Kacper Ratajczak-2026-03-30

    Analysis of FvncBot campaign

    CERT Polska has analyzed new samples associated with the FvncBot campaign targeting Polish users. This write-up is based on an SGB-branded variant.

    The campaign samples are hosted onruvofech.it[.]com, with no identified distribution source (as of the analysis date).

    The app presents itself asToken U2F Mobilna Ochrona SGB, claims that aPlay Componentis required, and then guides the victim through the installation of a hidden second-stage application labeledAndroid V.28.11. After that, the victim is pushed into enabling an accessibility service presented asSystem Update. Once enabled, the implant registers the device with the attacker-controlled backend and begins sending telemetry.

    The flow from the perspective of the victim that was captured during dynamic analysis is as follows:

    The user launches an application themed with the logo of one of the Polish banks (SGB). It is presented with a landing screen that displaysPlay ComponentRequired and prompts the user to pressInstall Component.

    Android opens theInstall unknown appsscreen for the app. The user is shown an installation prompt forAndroid V.28.11. After installation, the lure changes to anActivatebutton. Pressing it opens aSetup Requiredscreen that instructs the user to enable an accessibility service.

    After the service is enabled, the app displaysAll Systems Operational. In this campaign, all samples use different banks as disguises.

    This is the key social-engineering pattern in this campaign: the visible bank-themed lure does not perform the final malicious activity itself. Instead, it installs and activates a second-stage implant that hides behind Android/system default branding.

    Every Android application starts with anAndroidManifest.xmlfile. In this case, the manifest already shows that the outer SGB-branded app is designed to work with another package,com.core.town, and its provider.

    The strings shown to the victim are not incidental; they are the operator’s guided installation flow:

    The outer application class initializes the private directories and file name used for runtime loading:

    It also decodes staged content and forwards control into a reflective loader helper:

    The helper is explicit about the loading mechanism and specifically usesDexClassLoader:

    Dynamic analysis confirmed the exact runtime path:

    The runtime-loaded installer stage (com.gallery.oppose) stores several important values in Base64+XOR form. Once decoded, they reveal:

    The decoder itself is straightforward:

    The installer checks the second-stage provider to see whether accessibility is already enabled:

    It writes the embedded APK directly from assets and launches installation:

    After installation, it hands off control to the second stage through a deep link:

    This stage also reports key user actions back to the backend. The event schema includes build ID, package name, app version, device ID, Android version, and device model:

    The installer explicitly tracks at least these milestones:

    The embedded second-stage APK is not just a decoy package. Its manifest declares an accessibility implant with persistence, screen capture, Firebase messaging, and a provider used by the installer stage.

    Its accessibility profile is intentionally broad:

    The strings show the second-stage masquerade clearly. Second-stage tries to appear as a system update component:

    The most important deeper finding is thatcom.core.townis still not the end of the chain. ItsApplicationclass does more than just initialize the app: it extracts a hidden asset namedqkcCg.jpg, processes it, and loads another stage from it.

    ItsattachBaseContext()builds the internal path for that file and only continues if the nested unpacking succeeds:

    The helper extracted fromclasses7.dexshows thatqkcCg.jpgis not an image in any meaningful sense. The loader uses a small reflection/string-decoder layer and a hardcoded key string:

    The helper also contains a trivial XOR string decoder used for recovering the reflective method names:

    The actual transform routine usesthis.m.getBytes()and then performs an RC4-style key-scheduling and output loop:

    Offline reproduction confirmed that applying RC4 with keysDjCMto the rawqkcCg.jpgasset yields a valid ZIP archive whose only entry is the finalclasses.dex.

    The extracted final stage is where the actual implant behavior lives. It still uses thecom.core.townpackage namespace, but it is no longer just a setup shell.

    The finalRemoteAccessibilityServiceexecutes broadcast-delivered control messages and maps them to gesture injection and global actions:

    Touch injection is implemented withdispatchGesture():

    Global navigation actions are also exposed:

    The websocket binary decoder confirms that these are operator-triggered remote actions:

    The implant captures text changes from editable fields and records both the previous and updated values:

    The same event is also pushed into the implant's event/log channel:

    The general accessibility hook also capturesTYPE_VIEW_TEXT_CHANGEDdirectly:

    The service builds a full JSON representation of the current screen, including text, content descriptions, view IDs, screen bounds, roles, and children:

    The exported method returns the serialized tree with screen dimensions:

    The operator can instruct the implant to display URL, HTML, black-screen, or loading overlays:

    The FCM command set explicitly supports clickable overlays and overlay task updates:

    The overlay path also injects custom JavaScript into WebView content to keep input fields visible while the keyboard is open, which is consistent with credential-capture overlays.

    The implant can request MediaProjection permission and start a foreground capture service:

    The FCM command handler supports enabling live websocket sessions:

    That method accepts a per-session websocket URL and API key:

    The websocket client is built with OkHttp and addsX-API-Keywhen present:

    The binary control protocol is also visible in source. Examples:

    Relevant decoder fragment:

    The final-stage command set also includes:

    These are visible directly in the FCM command switch:

    The dynamic session confirms the static picture.

    Observed backend traffic:

    Observed enrollment values:

    Observed authentication headers:

    The static backend base URL is also embedded directly in the final-stage code. The final implant decodes the backend constant using an XOR helper and the keyzext0sup3bei25jm:

    Decoded value:

    The registration flow itself is explicitly in the source:

    After registration, the backend credentials are stored locally:

    The HTTP helper uses bothX-API-KeyandX-Device-IDfor authentication:

    The same client is used for command polling, heartbeat, and event batching:

    This sample is best understood as a multi-stage remote-control implant chain rather than a simple fake banking app. The SGB-branded lure, the runtime installer, the visibleAndroid V.28.11package, and the hiddenqkcCg.jpgstage are all part of one operator pipeline whose end goal is a fully enrolled accessibility implant.

    The samples previously analyzed by CERT Polska uses the same core staging model: a bank-themed lure, a runtime installer, handoff intocom.core.town, backend registration atjeliornic.it.com, and the same accessibility-centered implant design. The SGB variant therefore should be treated as another branch of the same FvncBot campaign, not as an unrelated one-off sample.

    Original source