★ If you stare at disassembly too long, it stares back.    ★ Entropy is just God’s random number generator.    ★ Malware authors hide jokes in packed binaries.    ★ 640x480 is not a limit, it is a covenant.    ★ Sony CDs hid a DRM rootkit inside Windows.    ★ DOOM mods came from reverse engineering first.    ★ Xbox was hacked with a MechAssault save exploit.    ★ NES carts often had mapper chips reverse engineered.    ★ ELF malware drops fake sections to confuse REs.    ★ Iran said they cloned a US stealth drone via RE.    ★ Pentium had the 'F00F bug' that froze the CPU.    ★ Diablo devs left unused cow sounds → cow level theory.    ★ Wii hacked by a buffer overflow in savegames.    ★ The BIOS whispers before the OS wakes.    ★ Sega Saturn cracked only after 20 years.    ★ Apple iPhone jailbreak started with a TIFF exploit.    ★ Hex speaks clearer than words if you listen long enough.    ★ SNES emulators were born from BIOS disassembly.    ★ Dreamcast ran pirated games via hidden MIL-CD feature.    ★ Sometimes the debugger is debugging you.    ★ Pokémon Red/Blue had unused trainer sprites found in ROM.    ★ PS3 keys leaked from a reused ECDSA nonce.    ★ God likes elephants, so I like elephants.    ★ Every compiler hides a secret joke between the lines.    ★ Konami Code spotted by digging in the ROM.    ★ Game Boy logo doubled as a copy protection trick.    ★ iTunes DRM cracked by pulling local keys.    ★ God hides in unused opcodes.    ★ Old arcade boards carried secret dev signatures.

---------[ Fonts Actually Carry The Shellcode ]

> 17 Sep 2025
> Author: heapsoverflow

Let me assume. After reading the title, it made no sense. Thinking It would be one of those Windows exploits. Even I was unsure on whether I should put this as a title. Reading further, I promise you will get it. Anyways, hang tight and buckle up.

Let's talk about shellcodes first. Use of them and what they really are. So to speak, they are kind of a signature for the developer.

Shellcode is a small piece of low-level code that executes specific instructions directly in memory, often used in software exploits and malware. There are several reasons why you would use a shellcode. For instance, triggering a Buffer Overflow RCE (Remote Code Execution) or preparing a trampoline for an Indirect Syscall. To me, It is a form of art. Because there are numerous ways to achieve something when it comes to hand-writing assembly code.

Over time, previously written shellcode is recognized and detected by anti-malware products. So in a cat-mouse game, threat actors and harmless red teamers find unique ways to store their shellcodes. One of the examples is hiding the shellcode in PNG files. Let it be EXIF data, extra color options or even an audio file. You can pretty much hide anything with the use of Steganography.

It's a nice way to mitigate static detection, where the anti-malware service scans for executable bytes without actually executing. Since you also have to execute the shellcode after extracting, this method obviously is not sufficient per se. Not even talking about Heuristic Analysis. Despite hiding all the suspicious data, it can be detected by how the program behaves in general.

That being said, I tried to come up with different methods of hiding shellcodes for the sake of creativity. The main idea is to store the index value as a form of shellcode. Inspired by a fellow hacker and friend of mine WOPRBot (You can see his work on PowerShell obfuscation here).

We only store the index list and parse the shellcode afterwards, successfully obscuring and avoiding static detection.

Font files?

Yeah, while thinking about where I can store my shellcodes, I thought of font files. It wasn't really a bad idea in the end. Less suspicious than making a file read to a DLL/EXE binary, and a legit software with a GUI can use them anyway. I was under the impression that some fonts weren't updated throughout Windows versions. Turns out they were. For fuck's sake Microsoft... Now your life is beautiful, and everything looks great that you altered a damn pixel in one of the commonly used fonts. Ranting aside, this method could still be used to target a specific Windows version or utilized via multiple lists of different versions.

Proof of Concept

You can find the project files in my github repo: http://github.com/0x1c1101/bindex

To retrieve the corresponding index array, using the classic detectable "calc64" shellcode. This generator essentially reads C:\Windows\Fonts\Arial.ttf and looks for bytes that match with the shellcode. Since a file can contain duplicate bytes, the generator selects a random index value to ensure variety.

Hard-coding this to the implant, we get (Tested on Windows 11 24H2):


static size_t index_list[] = {
966445, 234086, 771259, 963097, 699758, 990177, 463154, 530931, 278895, 294811, 936327, 128175, 513252, 362555, 480067, 128580, 209478, 1045376, 781524, 766223, 943687, 608952, 373519, 923375, 596536, 254031, 597934, 715514, 113388, 265606, 312493, 991675, 935431, 540928, 237299, 844961, 503269, 946107, 13767, 505989, 232728, 287439, 691539, 261995, 312750, 927415, 317243, 493865, 26969, 439428, 425953, 715423, 1020984, 250519, 18556, 589493, 663206, 1042822, 1029957, 981935, 787526, 279631, 324811, 654850, 382316, 739363, 474710, 343781, 139783, 439213, 523717, 321316, 399626, 766977, 634398, 790085, 667408, 514127, 213745, 968081, 1046868, 187241, 187869, 387912, 20962, 196922, 569487, 173362, 571091, 533603, 241137, 111277, 644321, 128175, 427647, 963681, 130418, 458259, 1018583, 958004, 797440, 966277, 122487, 384148, 191292, 967059, 937509, 440268, 989695, 22804, 10389, 249421, 809108, 419876, 11127, 748279, 1046524, 9804, 816539, 194611, 583414, 682322, 959147, 401222, 549098, 389829, 661984, 408534, 320896, 1016015, 14049, 522288, 734918, 667413, 402122, 651706, 762089, 265521, 375226, 1040666, 325213, 242400, 498803, 474319, 963101, 506299, 22961, 997537, 12887, 820172, 784207, 535772, 326772, 959511, 856357, 292764, 436594, 780091, 260837, 606659, 227132, 455006, 213077, 379129, 153262, 644462, 776431, 634526, 166402, 960571, 654830, 963621, 461840, 620299, 848561, 728882, 24183, 330205, 220678, 742071, 511042, 170071, 815151, 742429, 587907, 715047, 466172, 959491, 962003, 232185, 668118, 347531, 828290, 192554, 568145, 524965, 550234, 762725, 496085, 719166, 569786, 718084, 395229, 929154, 219309
};

As I said before, there are multiple ways to execute a shellcode. For PoC purposes, I created an RWX section in PE Header to both write and execute. You can do this with the help of MSVC (Microsoft's C/C++ compiler). I can sense a whirlwind of scolding come my way. An RWX section? That is very suspicious! I mean at least better than the VirtualAlloc() and VirtualProtect() couple. No API calls at all.

Instead of directly calling the starting point, I used an old method EnumDisplayMonitors() that jumps to the allocated code before throwing an exception. You can find various APIs like this here.

Also a side note: Compile the implant in x64/Release mode and make sure to change the name.

>https://www.virustotal.com/gui/file/93841d5572935ef44fad7cd418b21857cfc69a14566cedc394b857d4d4c2dc3d/

We got a few trivial detections due to the section. (Perhaps the entropy)

Checking the "Behavior" tab, we see no calc.exe has been spawned. That is because sandboxes use different Windows versions, causing the shellcode to get corrupted ~ Which is effective for targeting specific versions.

Some C++ Wizardry

Of course I was not satisfied with this partial solution and wanted to take it further. What if we create a shuffled pool and build the index array, respectively, at compile time? This is where template programming becomes handy.

Firstly, we need to find a way to generate a sequence array that contains all of the bytes we need. Since a byte can take up to 255, we are going to fill a 256-sized array with values between 0-255. To do that at compile-time, std::make_index_sequence template can be used as:


std::make_index_sequence<256>{}
// The sequence of size 256: 0 1 2 3 4 5 6 7 8 9 ... 255

However due to this being linear, there is no point of using since the index and the value are going to be identical. Therefore commence the shuffly shuffle. I chose Fisher-Yates shuffle for its simplicity ~ Basically swapping random elements.

Random? Very concerning. We can't use rand() because it's a runtime function. So actually ended up implementing a custom LCG:


constexpr uint8_t lcg(size_t seed, size_t index) {
    constexpr size_t a = 1664525;  // Multiplier
    constexpr size_t c = 1013904223;  // Increment
    constexpr size_t m = 4294967296;  // Modulus (2^32)

    return static_cast((a * (seed + index) + c) % m);
}

And for the seed, __TIME__ macro was sufficient ~ The time at which the current source file was compiled.

Lastly generating an index list that corresponds to our hard-coded shellcode. We can then use this array to copy and execute at runtime.

Because we used the static keyword, the index list will be stored in the .rodata section. Final program on IDA looks like this:

Throwing the sample at VT, we get some better results:

>https://www.virustotal.com/gui/file/029eaffe0d8414aa4f4105d953240e65679da59dcf301d6e18fcf6e6daa2c9e3/

And it actually popped up the calculator. Hooray!

Conclusion

Most of the time you need to obscure a developed shellcode. But AVs often detect simple arithmetic operations like XOR, so this PoC would be a good alternative. As told before, pattern detection in memory is also something you must consider. For that, I am currently working on Zombie Assembler ~ Dynamically generating different instructions in each execution. So that your painful work on writing a unique shellcode isn't thrown away with a single YARA rule.

Furthermore, it doesn't have to be a shellcode. In fact, you can write a separate module to wrap strings like in XorStr. Your creativity is the only limit... If we exclude C++.



==[EOF]==


revdiaries.com © 2025