ایجاد بایت‌کدهای ماشین با زبان اسمبلی برای Shell Code

برای ایجاد بایت‌کدهای ماشین، می‌توانید از زبان اسمبلی استفاده کنید و سپس کد اسمبلی را به بایت‌کد ماشین تبدیل کنید. ابزارهایی مانند nasm (Netwide Assembler).....

انتشار: , زمان مطالعه: 7 دقیقه
ایجاد بایت‌کدهای ماشین با زبان اسمبلی برای  Shell Code
دسته بندی: امنیت سایبری تعداد بازدید: 180

آموزش ایجاد بایت‌کدهای ماشین با زبان اسمبلی برای  Shell Code

برای ایجاد بایت‌کدهای ماشین، می‌توانید از زبان اسمبلی استفاده کنید و سپس کد اسمبلی را به بایت‌کد ماشین تبدیل کنید. ابزارهایی مانند nasm (Netwide Assembler) برای این کار بسیار مناسب هستند. در اینجا مثالی از کد اسمبلی که یک پیام باکس نمایش می‌دهد آورده شده است:

کد اسمبلی برای نمایش MessageBox

section .data
    msg db 'Hello, World!', 0  ; Programmer: Ebrahim Shafiei (EbraSha)

section .text
    global _start

_start:
    ; Write message to stdout
    mov eax, 4          ; syscall number for sys_write
    mov ebx, 1          ; file descriptor 1 is stdout
    mov ecx, msg        ; pointer to message
    mov edx, 13         ; message length
    int 0x80            ; call kernel
    ; Programmer: Ebrahim Shafiei (EbraSha)

    ; Exit program
    mov eax, 1          ; syscall number for sys_exit
    xor ebx, ebx        ; exit code 0
    int 0x80            ; call kernel
    ; Programmer: Ebrahim Shafiei (EbraSha)

تبدیل کد اسمبلی به بایت‌کد ماشین

برای تبدیل این کد اسمبلی به بایت‌کد ماشین، می‌توانید از اسمبلر nasm استفاده کنید:

nasm -f bin -o shellcode.bin messagebox.asm

پس از تولید فایل shellcode.bin، می‌توانید بایت‌کدهای ماشین را با استفاده از یک ابزار مانند xxd به آرایه بایت‌ها در C++ تبدیل کنید:

xxd -i shellcode.bin

استفاده از بایت‌کدهای ماشین در برنامه C++

آرایه بایت‌های تولید شده را می‌توانید مستقیماً در برنامه C++ خود قرار دهید:

unsigned char shellcode[] = {
// Bytecodes generated by xxd
};

این بایت‌کدها همان کدهای ماشین هستند که مستقیماً توسط پردازنده اجرا می‌شوند. با این روش، می‌توانید هر کدی را که می‌خواهید در برنامه C++ خود اجرا کنید، به شرطی که بایت‌کدهای آن را داشته باشید.

تحلیل و توضیح کد اسمبلی برای نمایش MessageBox

این کد اسمبلی با استفاده از دستورالعمل‌های سطح پایین و API های ویندوز، یک پیام باکس با متن "Hello, World!" نمایش می‌دهد و سپس برنامه را خاتمه می‌دهد. کد شامل سه بخش اصلی است: .data، .text و .idata.

بخش .data

section .data
    msg db 'Hello, World!', 0
  • section .data: این بخش داده‌های ایستا (ثابت) برنامه را ذخیره می‌کند.
  • msg db 'Hello, World!', 0: این خط یک رشته‌ای از کاراکترها که متن "Hello, World!" را شامل می‌شود و با بایت صفر (null terminator) خاتمه می‌یابد، تعریف می‌کند.

بخش .text

section .text
    global _start

_start:
    ; Load user32.dll
    xor  eax, eax
    push eax
    push 0x646c6c61 ; 'alla'
    push 0x642e3233 ; 'd.32'
    push esp
    mov  ebx, esp
    call dword ptr [LoadLibraryA]

    ; Load MessageBoxA
    xor  eax, eax
    push eax
    push 0x41786541 ; 'Aexe'
    push 0x42656761 ; 'Bega'
    push 0x7373654d ; 'sseM'
    push esp
    mov  ebx, esp
    call dword ptr [GetProcAddress]

    ; Call MessageBoxA
    xor  ecx, ecx
    push ecx
    push ecx
    push msg
    push ecx
    call eax

    ; Exit process
    xor  eax, eax
    inc  eax
    push eax
    call dword ptr [ExitProcess]
  • section .text: این بخش کدهای اجرایی (دستورات) برنامه را شامل می‌شود.
  • global _start: این خط نشان می‌دهد که _start نقطه ورودی برنامه است.
  • _start:: نقطه ورودی برنامه.

بارگذاری user32.dll

    xor  eax, eax
    push eax
    push 0x646c6c61 ; 'alla'
    push 0x642e3233 ; 'd.32'
    push esp
    mov  ebx, esp
    call dword ptr [LoadLibraryA]
  • xor eax, eax: مقدار رجیستر eax را صفر می‌کند.
  • push eax: مقدار صفر (نشان‌دهنده پایان رشته) را به پشته فشار می‌دهد.
  • push 0x646c6c61 و push 0x642e3233: حروف ASCII برای "alla" و "d.32" را به صورت برعکس (به دلیل لیتل اندین) به پشته فشار می‌دهد، که در نهایت user32.dll می‌سازد.
  • push esp: آدرس استک پویینتر (ESP) که حاوی آدرس نام DLL است را به پشته فشار می‌دهد.
  • mov ebx, esp: مقدار رجیستر ebx را با آدرس نام DLL تنظیم می‌کند.
  • call dword ptr [LoadLibraryA]: تابع LoadLibraryA را فراخوانی می‌کند تا user32.dll را بارگذاری کند.

بارگذاری MessageBoxA

    xor  eax, eax
    push eax
    push 0x41786541 ; 'Aexe'
    push 0x42656761 ; 'Bega'
    push 0x7373654d ; 'sseM'
    push esp
    mov  ebx, esp
    call dword ptr [GetProcAddress]
  • xor eax, eax: مقدار رجیستر eax را صفر می‌کند.
  • push eax: مقدار صفر (نشان‌دهنده پایان رشته) را به پشته فشار می‌دهد.
  • push 0x41786541، push 0x42656761 و push 0x7373654d: حروف ASCII برای "Aexe"، "Bega" و "sseM" را به صورت برعکس به پشته فشار می‌دهد که در نهایت MessageBoxA را می‌سازد.
  • push esp: آدرس استک پویینتر (ESP) که حاوی آدرس نام تابع است را به پشته فشار می‌دهد.
  • mov ebx, esp: مقدار رجیستر ebx را با آدرس نام تابع تنظیم می‌کند.
  • call dword ptr [GetProcAddress]: تابع GetProcAddress را فراخوانی می‌کند تا آدرس تابع MessageBoxA را بگیرد.

فراخوانی MessageBoxA

    xor  ecx, ecx
    push ecx
    push ecx
    push msg
    push ecx
    call eax
  • xor ecx, ecx: مقدار رجیستر ecx را صفر می‌کند.
  • push ecx: مقدار صفر را به پشته فشار می‌دهد (به عنوان آخرین پارامتر MessageBoxA که uType است).
  • push ecx: دوباره مقدار صفر را به پشته فشار می‌دهد (به عنوان پارامتر hWnd).
  • push msg: آدرس پیغام "Hello, World!" را به پشته فشار می‌دهد (به عنوان پارامتر lpText).
  • push ecx: مقدار صفر را به پشته فشار می‌دهد (به عنوان پارامتر lpCaption).
  • call eax: فراخوانی تابع MessageBoxA.

خاتمه برنامه

    xor  eax, eax
    inc  eax
    push eax
    call dword ptr [ExitProcess]
  • xor eax, eax: مقدار رجیستر eax را صفر می‌کند.
  • inc eax: مقدار eax را به 1 افزایش می‌دهد.
  • push eax: مقدار 1 (کد خروج) را به پشته فشار می‌دهد.
  • call dword ptr [ExitProcess]: تابع ExitProcess را فراخوانی می‌کند تا برنامه را خاتمه دهد.

بخش .idata

section .idata
    dd 0,0,0,RVA kernel32_str,RVA kernel32_table
    dd 0,0,0,RVA user32_str,RVA user32_table
    dd 0,0,0,0,0

kernel32_table:
    ExitProcess dd RVA ExitProcess_str
    LoadLibraryA dd RVA LoadLibraryA_str
    GetProcAddress dd RVA GetProcAddress_str
    dd 0

user32_table:
    MessageBoxA dd RVA MessageBoxA_str
    dd 0

kernel32_str db 'KERNEL32.DLL',0
user32_str db 'USER32.DLL',0

ExitProcess_str db 'ExitProcess',0
LoadLibraryA_str db 'LoadLibraryA',0
GetProcAddress_str db 'GetProcAddress',0
MessageBoxA_str db 'MessageBoxA',0
  • section .idata: این بخش داده‌های ایمپورت (وارداتی) برنامه را شامل می‌شود.
  • این بخش شامل جداول و رشته‌هایی است که نام توابع و DLLهای مورد استفاده را ذخیره می‌کنند.

با استفاده از این کد، یک برنامه اسمبلی ساده ایجاد می‌شود که با استفاده از APIهای ویندوز، یک پیام باکس نمایش می‌دهد و سپس برنامه را خاتمه می‌دهد. این کد نشان‌دهنده چگونگی بارگذاری DLLها، پیدا کردن توابع و استفاده از آنها در سطح پایین است.


دیدگاه های مربوط به این مقاله (برای ارسال دیدگاه در سایت حتما باید عضو باشید و پروفایل کاربری شما تکمیل شده باشد)