Window中的shellcode編寫框架(入門篇)

来源:https://www.cnblogs.com/thresh/archive/2020/03/31/12609659.html
-Advertisement-
Play Games

Shellcode 定義 是一段可註入的指令(opcode),可以在被攻擊的程式內運行。 特點 短小精悍,靈活多變,獨立存在,無需任何文件格式的包裝,因為shellcode直接操作寄存器和函數,所以opcode必須是16進位形式。因此也不能用高級語言編寫shellcode。在記憶體中運行,無需運行在固 ...


Shellcode

  • 定義

  是一段可註入的指令(opcode),可以在被攻擊的程式內運行。

  • 特點

  短小精悍,靈活多變,獨立存在,無需任何文件格式的包裝,因為shellcode直接操作寄存器和函數,所以opcode必須是16進位形式。因此也不能用高級語言編寫shellcode。在記憶體中運行,無需運行在固定的宿主進程上。

  • Shellcode的利用原理

  將shellcode註入緩衝區,然後欺騙目標程式執行它。而將shellcode註入緩衝區最常用的方法是利用目標系統上的緩衝區溢出漏洞。

Shellcode生成方法

  • 編程語言編寫:彙編語言,C語言
  • shellcode生成器

Shellcode編寫原則

  •  杜絕雙引號字元串的直接使用

    關閉VS自動優化沒有使用到的變數

    自定義函數入口

  •   動態獲取函數的地址

    GetProAddress 從dll中獲取函數的地址

    參數1:調用dll的句柄,參數2:函數名

    Bug:error C2760: 語法錯誤: 意外的令牌“標識符”,預期的令牌為“類型說明符”

    打開項目工程-> 屬性 -> c/c++ --> 語言 -> 符合模式 修改成否即可 如果這樣設置將無法使用c函數。

    這個比較關鍵,否則使用printf就直接崩潰或者是編譯報錯

    最佳方案是:修改平臺工具集

  • 通過獲得Kernel32基址來獲取GetProcAddres基址
  • 避免全局變數的使用

    因為vs會將全局變數編譯在其他區段中 結果就是一個絕對的地址不能使用static定義變數(變數放到內部函數使用)

  •  確保已載入使用API的動態鏈接庫

編寫shellcode前的準備

  • 修改程式入口點:鏈接器-高級。作用:去除自動生成的多餘的exe代碼
  • 關閉緩衝區安全檢查,屬性->C/C++ ->代碼生成->安全檢查禁用
  • 設置工程相容window XP :代碼生成 ->運行庫 選擇 debug MTD  release MT
  • 清除資源:鏈接器->調試->清單文件
  • 關閉調試功能

如下:

 

屬性->常規->平臺工具集 選擇xp版本

 

 

 

 

C/C++->代碼生成->運行庫選擇MT

安全檢查禁用

 

 

 

 

 

鏈接器->高級->入口點修改為EntryMain

 

 

 

 

 

函數動態鏈接調用

  在編寫shellcode時,所有用到的函數都需要動態調用,通過LoadLibrary函數載入動態鏈接庫,GetProAddress獲取動態鏈接庫中函數的地址。所以獲取到GetProAddress和LoadLibrary地址時非常重要的。通過GetProAddress和LoadLibrary,可以獲取到已載入的動態鏈接庫的地址。

 

動態獲取Kernel32.dll基址和GetProAddress 地址

  在正常情況下,我們不知道LoadLibraryA的地址,所以不能直接使用該函數。GetProAddress是動態鏈接庫Kernel32.dll中的函數。每個進程內部載入都會載入Kernel32.dll,獲取到載入Kernel32.dll地址就可以獲取到GetProAddress函數的地址。通過彙編內嵌獲取到Kernel32的基址。獲取到GetProAddress地址後,就可以獲取到所有需要的函數的地址。

 

pE文件運行時載入的鏈接庫

 

 

 

 

代碼如下:

#include <windows.h>
#include <stdio.h>

//內嵌彙編獲取Kernel32的地址
__declspec(naked) DWORD getKernel32()
{
    __asm
    {
        mov eax,fs:[30h]
        mov eax,[eax+0ch]
        mov eax,[eax+14h]
        mov eax,[eax]
        mov eax,[eax]
        mov eax,[eax+10h]
        ret
    }
}

//通過kernel32基址獲取GetProcAddress的地址
FARPROC _GetProcAddress(HMODULE hModuleBase) 
{
    PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
    PIMAGE_NT_HEADERS32 lpNtHeader = (PIMAGE_NT_HEADERS)((DWORD)hModuleBase + lpDosHeader->e_lfanew);
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size){
        return NULL;
    }
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
        return NULL;
    }
    PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase + (DWORD)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    PDWORD lpdwFunName = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNames);
    PWORD lpword = (PWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNameOrdinals);
    PDWORD lpdwFunAddr = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfFunctions);

    DWORD dwLoop = 0;
    FARPROC pRet = NULL;
    for (; dwLoop <= lpExports->NumberOfNames - 1; dwLoop++) {
        char* pFunName = (char*)(lpdwFunName[dwLoop] + (DWORD)hModuleBase);

        if (pFunName[0] == 'G'&&
            pFunName[1] == 'e'&&
            pFunName[2] == 't'&&
            pFunName[3] == 'P'&&
            pFunName[4] == 'r'&&
            pFunName[5] == 'o'&&
            pFunName[6] == 'c'&&
            pFunName[7] == 'A'&&
            pFunName[8] == 'd'&&
            pFunName[9] == 'd'&&
            pFunName[10] == 'r'&&
            pFunName[11] == 'e'&&
            pFunName[12] == 's'&&
            pFunName[13] == 's')
        {
            pRet = (FARPROC)(lpdwFunAddr[lpword[dwLoop]] + (DWORD)hModuleBase);
            break;
        }
    }
    return pRet;
}

int main()
{
    //kernel32.dll 基址的動態獲取
    HMODULE hLoadLibrary = LoadLibraryA("kernel32.dll");
    //使用內嵌彙編來獲取基址
    HMODULE _hLoadLibrary = (HMODULE)getKernel32();
    //效果是一樣的
    printf("LoadLibraryA動態獲取的地址: 0x%x\n", hLoadLibrary);
    printf("內嵌彙編獲取的地址: 0x%x\n", _hLoadLibrary);

    //聲明定義,先轉到到原函數定義,然後重新定義
    typedef FARPROC(WINAPI *FN_GetProcAddress)(
            _In_ HMODULE hModule,
            _In_ LPCSTR lpProcName
        );

    FN_GetProcAddress fn_GetProcAddress;
    fn_GetProcAddress = (FN_GetProcAddress)_GetProcAddress(_hLoadLibrary);

    printf("動態獲取GetProcAddress地址: 0x%x\n",fn_GetProcAddress);
    printf("內置函數獲取: 0x%x\n",GetProcAddress);
}

 

可以看到,動態獲取的地址和系統函數獲取的是一致的

 

 

 

 

Shellcode框架(一)

引用前面kernel32.dll和GetProcaddress的獲取地址。對於每一個要引用的函數,通過查看定義來聲明定義函數,通過GetProcaddress動態獲取地址。

 

 

具體代碼如下:

原C代碼:

#include <windows.h>
#include <stdio.h>
#include <windows.h>
int EntryMain()
{
CreateFileA(“1.txt”, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
MessageBoxA(NULL, “hello world”, tip, MB_OK);
return 0;
}

Shellcode編寫:

#include <windows.h>
#include <stdio.h>

FARPROC  getProcAddress(HMODULE hModuleBase);
DWORD getKernel32();

int EntryMain()
{
    //聲明定義GetProcAddress
    typedef FARPROC(WINAPI *FN_GetProcAddress)(
        _In_ HMODULE hModule,
        _In_ LPCSTR lpProcName
        );

    //獲取GetProcAddress真實地址
    FN_GetProcAddress fn_GetProcAddress = (FN_GetProcAddress)getProcAddress((HMODULE)getKernel32());


    //聲明定義CreateFileA
    typedef HANDLE(WINAPI *FN_CreateFileA)(
            __in     LPCSTR lpFileName,
            __in     DWORD dwDesiredAccess,
            __in     DWORD dwShareMode,
            __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
            __in     DWORD dwCreationDisposition,
            __in     DWORD dwFlagsAndAttributes,
            __in_opt HANDLE hTemplateFile
        );
    //將來的替換,地址全部動態獲取
    //FN_CreateFileA fn_CreateFileA = (FN_CreateFileA)GetProcAddress(LoadLibrary("kernel32.dll"), "CreateFileA");
    //帶引號的字元串打散處理
    char xyCreateFile[] = { 'C','r','e','a','t','e','F','i','l','e','A',0 };
    //動態獲取CreateFile的地址
    FN_CreateFileA fn_CreateFileA = (FN_CreateFileA)fn_GetProcAddress((HMODULE)getKernel32(), xyCreateFile);
    char xyNewFile[] = { '1','.','t','x','t','\0'};
    fn_CreateFileA(xyNewFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);


    //定義LoadLibraryA
    typedef HMODULE(WINAPI *FN_LoadLibraryA)(
            __in LPCSTR lpLibFileName
        );
    char xyLoadLibraryA[] = { 'L','o','a','d','L','i','b','r','a','r','y','A',0};
    //動態獲取LoadLibraryA的地址
    FN_LoadLibraryA fn_LoadLibraryA = (FN_LoadLibraryA)fn_GetProcAddress((HMODULE)getKernel32(), xyLoadLibraryA);


    //定義MessageBoxA
    typedef int (WINAPI *FN_MessageBoxA)(
            __in_opt HWND hWnd,
            __in_opt LPCSTR lpText,
            __in_opt LPCSTR lpCaption,
            __in UINT uType);

            //原來的:MessageBoxA(NULL, "Hello world", "tip", MB_OK);
            char xy_user32[] = { 'u','s','e','r','3','2','.','d','l','l',0 };
            char xy_MessageBoxA[] = { 'M','e','s','s','a','g','e','B','o','x','A',0 };
            FN_MessageBoxA fn_MessageBoxA = (FN_MessageBoxA)fn_GetProcAddress(fn_LoadLibraryA(xy_user32), xy_MessageBoxA);
            char xy_Hello[] = { 'H','e','l','l','o',' ','w','o','r','l','d',0 };
            char xy_tip[] = { 't','i','p' };
            fn_MessageBoxA(NULL, xy_Hello, xy_tip, MB_OK);
            return 0;
}

//內嵌彙編獲取Kernel32的地址
__declspec(naked) DWORD getKernel32()
{
    __asm
    {
        mov eax, fs:[30h]
        mov eax, [eax + 0ch]
        mov eax, [eax + 14h]
        mov eax, [eax]
        mov eax, [eax]
        mov eax, [eax + 10h]
        ret
    }
}

//獲取GetProcAddress的地址
FARPROC getProcAddress(HMODULE hModuleBase)
{
    PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
    PIMAGE_NT_HEADERS32 lpNtHeader = (PIMAGE_NT_HEADERS)((DWORD)hModuleBase + lpDosHeader->e_lfanew);
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) {
        return NULL;
    }
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
        return NULL;
    }
    PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase + (DWORD)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    PDWORD lpdwFunName = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNames);
    PWORD lpword = (PWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNameOrdinals);
    PDWORD lpdwFunAddr = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfFunctions);

    DWORD dwLoop = 0;
    FARPROC pRet = NULL;
    for (; dwLoop <= lpExports->NumberOfNames - 1; dwLoop++) {
        char* pFunName = (char*)(lpdwFunName[dwLoop] + (DWORD)hModuleBase);

        if (pFunName[0] == 'G'&&
            pFunName[1] == 'e'&&
            pFunName[2] == 't'&&
            pFunName[3] == 'P'&&
            pFunName[4] == 'r'&&
            pFunName[5] == 'o'&&
            pFunName[6] == 'c'&&
            pFunName[7] == 'A'&&
            pFunName[8] == 'd'&&
            pFunName[9] == 'd'&&
            pFunName[10] == 'r'&&
            pFunName[11] == 'e'&&
            pFunName[12] == 's'&&
            pFunName[13] == 's')
        {
            pRet = (FARPROC)(lpdwFunAddr[lpword[dwLoop]] + (DWORD)hModuleBase);
            break;
        }
    }
    return pRet;
}

  結果:運行exe文件創建了1.txt文件,並出現彈框。

 

 

 

 

 

函數生成的位置規律

  1. 單文件函數生成的位置規律

  規律:單文件函數的生成規律,與函數實現的先後順序有關,而與函數的定義順序無關。

  例如:

 

#include<windows.h>
#include<stdio.h>

int FuncA(int a, int b)
{
    puts("AAAA");
    return a + b;
}

int FuncB(int a, int b)
{
    puts("BBB");
    return a + b;
}
int main()
{
    FuncA(1, 2);
    FuncB(2, 3);
    return 0;
}

 

  結果:在IDA中看到生成的exe文件中的函數順序為FuncA,FuncB,main,與函數實現的先後順序有關。通過函數的位置,可以得到兩個函數之間的空間大小。

  2.多文件函數生成的位置規律

    規律:與包含文件的位置無關,與實際調用的順序有關

  //A.h
#include<stdio.h>
void A()
{
  puts("AAA");
}

//B.h
#include<stdio.h>
void B()
{
  puts("BBB");
}

//main
#include"A.h"
#include"B.h"
int main()

{ 
  A(); B();
return 0; }

 

  結果:

   

 

 

 

  工程下的尾碼名為vcxproj文件

   

 

 

 

  修改順序

   

 

 

 

  可以看到生成的順序發生了改變

  

Shellcode框架(二)

  Shellcode代碼執行過程

  ShellcodeStart-> ShellcodeEntry-> ShellcodeEnd

   工程文件:

  api.h文件:存放定義的的函數

  header.h文件:存放定義的功能函數

  0.entry.cpp文件:shellcode的入口點

  a.start.cpp文件:shellcode執行(實現邏輯功能)

  b.work.cpp文件:存放具體功能實現

  z.end.cpp文件:shellcode結束

 

  a.start.cpp文件和b.work.cpp文件分別管理邏輯功能和具體實現,更方便管理。

  生成的文件順序:

 

 

   

 

 

   代碼:

  api.h

#pragma once

#include<windows.h>

//聲明定義GetProcAddress
typedef FARPROC(WINAPI *FN_GetProcAddress)(
    _In_ HMODULE hModule,
    _In_ LPCSTR lpProcName
    );
//定義LoadLibraryA
typedef HMODULE(WINAPI *FN_LoadLibraryA)(
    __in LPCSTR lpLibFileName
    );

//定義MessageBoxA
typedef int (WINAPI *FN_MessageBoxA)(
    __in_opt HWND hWnd,
    __in_opt LPCSTR lpText,
    __in_opt LPCSTR lpCaption,
    __in UINT uType);

//定義CreateFileA
typedef HANDLE(WINAPI *FN_CreateFileA)(
    __in     LPCSTR lpFileName,
    __in     DWORD dwDesiredAccess,
    __in     DWORD dwShareMode,
    __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    __in     DWORD dwCreationDisposition,
    __in     DWORD dwFlagsAndAttributes,
    __in_opt HANDLE hTemplateFile
    );

//定義一個指針
typedef struct _FUNCTIONS
{
    FN_GetProcAddress fn_GetProcAddress;
    FN_LoadLibraryA fn_LoadLibraryA;
    FN_MessageBoxA fn_MessageBoxA;
    FN_CreateFileA fn_CreateFileA;
}FUNCTIONS,*PFUNCTIONS;

  header.h

#pragma once
#include<windows.h>
#include<stdio.h>
#include"api.h"
void ShellcodeStart();
void ShellcodeEntry();
void ShellcodeEnd();
void CreateShellcode();
void InitFunctions(PFUNCTIONS pFn);
void CreateConfigFile(PFUNCTIONS pFn);

  

  0.entry.cpp

  

#include "header.h"
int EntryMain()
{
    CreateShellcode();

    return 0;
}

void CreateShellcode() 
{

    HMODULE hMsvcrt = LoadLibraryA("msvcrt.dll");
    //定義printf
    typedef int (__CRTDECL *FN_printf)(
        _In_z_ _Printf_format_string_ char const* const _Format,
        ...);
    FN_printf fn_printf = (FN_printf)GetProcAddress(hMsvcrt,"printf");

    HANDLE hBin = CreateFileA("sh.bin", GENERIC_ALL, 0, NULL, CREATE_ALWAYS, 0, NULL);

    if (hBin == INVALID_HANDLE_VALUE)
    {

        //這裡不能使用printf函數,因為修改了函數入口,找不到printf的地址,所有需要動態調用printf函數
        //printf("create file error:%d\n", GetLastError());
        fn_printf("create file error:%d\n", GetLastError());
        return ;
    }
    DWORD dwSize = (DWORD)ShellcodeEnd - (DWORD)ShellcodeStart;
    DWORD dwWrite;
    WriteFile(hBin, ShellcodeStart, dwSize, &dwWrite, NULL);
    CloseHandle(hBin);

}

 a.start.cpp文件

#include "header.h"
#include "api.h"
__declspec(naked) void ShellcodeStart()
{
    __asm 
    {
        jmp ShellcodeEntry
    }
}
//內嵌彙編獲取Kernel32的地址
__declspec(naked) DWORD getKernel32()
{
    __asm
    {
        mov eax, fs:[30h];
        test eax, eax;
        js finished;
        mov eax, [eax + 0ch];
        mov eax, [eax + 14h];
        mov eax, [eax];
        mov eax, [eax]
        mov eax, [eax + 10h]
    finished:
        ret
    }
}

//獲取GetProcAddress的地址
FARPROC getProcAddress(HMODULE hModuleBase)
{
    PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
    PIMAGE_NT_HEADERS32 lpNtHeader = (PIMAGE_NT_HEADERS)((DWORD)hModuleBase + lpDosHeader->e_lfanew);
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) {
        return NULL;
    }
    if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
        return NULL;
    }
    PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase + (DWORD)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    PDWORD lpdwFunName = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNames);
    PWORD lpword = (PWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNameOrdinals);
    PDWORD lpdwFunAddr = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfFunctions);

    DWORD dwLoop = 0;
    FARPROC pRet = NULL;
    for (; dwLoop <= lpExports->NumberOfNames - 1; dwLoop++) {
        char* pFunName = (char*)(lpdwFunName[dwLoop] + (DWORD)hModuleBase);


        if (pFunName[0] == 'G'&&
            pFunName[1] == 'e'&&
            pFunName[2] == 't'&&
            pFunName[3] == 'P'&&
            pFunName[4] == 'r'&&
            pFunName[5] == 'o'&&
            pFunName[6] == 'c'&&
            pFunName[7] == 'A'&&
            pFunName[8] == 'd'&&
            pFunName[9] == 'd'&&
            pFunName[10] == 'r'&&
            pFunName[11] == 'e'&&
            pFunName[12] == 's'&&
            pFunName[13] == 's')
        {
            pRet = (FARPROC)(lpdwFunAddr[lpword[dwLoop]] + (DWORD)hModuleBase);
            break;
        }
    }
    return pRet;
}
//動態調用地址
void InitFunctions(PFUNCTIONS pFn) 
{
    //獲取GetProcAddress真實地址
    pFn->fn_GetProcAddress = (FN_GetProcAddress)getProcAddress((HMODULE)getKernel32());
    //動態獲取LoadLibraryA的地址
    char xyLoadLibraryA[] = { 'L','o','a','d','L','i','b','r','a','r','y','A',0 };
    pFn->fn_LoadLibraryA = (FN_LoadLibraryA)pFn->fn_GetProcAddress((HMODULE)getKernel32(), xyLoadLibraryA);
    
    //動態獲取MessageBoxA的地址
    char xy_user32[] = { 'u','s','e','r','3','2','.','d','l','l',0 };
    char xy_MessageBoxA[] = { 'M','e','s','s','a','g','e','B','o','x','A',0 };
    pFn->fn_MessageBoxA = (FN_MessageBoxA)pFn->fn_GetProcAddress(pFn->fn_LoadLibraryA(xy_user32), xy_MessageBoxA);

    //動態獲取CreateFile的地址
    char xyCreateFile[] = { 'C','r','e','a','t','F','i','l','e','A',0 };
    pFn->fn_CreateFileA = (FN_CreateFileA)pFn->fn_GetProcAddress((HMODULE)getKernel32(), xyCreateFile);

}
//入口點
void ShellcodeEntry()
{
    char xy_Hello[] = { 'H','e','l','l','o',' ','w','o','r','l','d',0 };
    char xy_tip[] = { 't','i','p' };
    FUNCTIONS fn;
    InitFunctions(&fn);
    CreateConfigFile(&fn);
}

  b.work.cpp

#include"api.h"
#include<stdio.h>
//存放功能
void CreateConfigFile(PFUNCTIONS pFn)
{
    char xyNewFile[] = { '1','.','t','x','t','\0' };
    pFn->fn_CreateFileA(xyNewFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
}

  z.end.cpp

#include "header.h"
void ShellcodeEnd()
{

}

Shellcode載入器

用來運行提取出來的shellcode代碼,保存在sh.bin文件,將sb.bin文件拖入載入器,即可執行。

#include<stdio.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("Oen 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;
}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • #coding:utf-8from module6 import shitprint("6、第六章,函數與模塊的使用\n函數結構:\ndef 函數名(參數名):\n\t語句1\n\t語句n\n\treturn 返回值\n註意:\n設置函數的時候,函數的參數是形式參數,調用函數的時候,函數的參數是實際 ...
  • #coding:utf-8import randomwhile True: xuanze=int(input("請輸入您想進入的題目:\n1、水仙花數\n2、百錢百雞\n4、退出\n(請輸入您的數字)")) if xuanze == 1: print("水仙花數") while True: whil ...
  • n=int(input("輸入你想列印幾行的三角形:"))+1for i in range(n): print(" "*(n-i)+ i*"*" + "*"*(i-1)) ...
  • print("3、第三章:分支結構\n(1)if語句的使用\nif 條件:\n\t語句1\nelse\n\t語句2\n含義:如果條件對,則執行語句1,如果條件不對,則執行語句2\n") ...
  • print("電腦硬體系統分五大部分組成:\n1、運算器\n2、控制器\n3、存儲器\n4、輸入設備\n5、輸出設備\n\n馮·諾依曼結構關鍵點:\n1、要將存儲設備與中央處理器分開;\n2、將數據以二進位方式編碼\n")print("變數和類型\n1、整形:python2.x中有int和long ...
  • print("1、第一章:初識python\npython歷史:\n1、python是用c語言寫的\n2、python是可以調用c語言庫函數\n3、Python1.0是1994年1月\n4、Python2.0是2000年10月16日\n5、Python3.0是2008年12月3日\n5、當前用的Py ...
  • 題目:企業發放的獎金根據利潤提成。 利潤(I)低於或等於10萬元時,獎金可提10%; 利潤高於10萬元,低於20萬元時,低於10萬元的部分按10%提成,高於10萬元的部分,可提成7.5%; 20萬到40萬之間時,高於20萬元的部分,可提成5%; 40萬到60萬之間時高於40萬元的部分,可提成3%; ...
  • Go語言中有豐富的數據類型,除了基本的整型、浮點型、布爾型、字元串外,還有數組、切片、結構體、函數、map、通道(channel)等。Go 語言的基本類型和其他語言大同小異。 1.基本數據類型 整型 整型分為以下兩個大類: 按長度分為:int8、int16、int32、int64 對應的無符號整型: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...