2012-11-07 11 views
5

Chcę móc przekonwertować pojedynczą linię ASM na kod powłoki. Tj:Jak uzyskać kod maszynowy instrukcji złożenia znanej podczas kompilacji?

CALL EBX 

Jak mogę to zabrać, a także jest w stanie poprawnie przekonwertować ten szelkod tak, że można przechowywać ją w zmiennej w aplikacji Delphi. Tj:

var ShellCodeArray: array[0..3] of Byte = ($55,$8B,$EC,$81); 
+2

Jeśli używasz języka z wbudowanym asemblerem, dlaczego nie używać tego asemblera? – hvd

+0

Różne powody. Ale dzięki za twoją odpowiedź. –

+1

szukasz czegoś takiego? http://www.delphibasics.info/home/delphibasicssnippets/executingpreparedshellcodeindelphi – bummi

Odpowiedz

5

Gdybym Ci rację, chcesz uzyskać kod maszynowy pojedynczej instrukcji asemblera CALL EBX użyciu Delphi wbudowany w asemblerze.

function CodeSize: Integer; 
asm 
    lea EAX, @@end 
    lea EDX, @@start 
    sub EAX, EDX 
    JMP @@end 
@@start: 
    call EBX 
@@end: 
end; 

procedure Code; 
asm 
    call EBX 
end; 

function CodeToBytes: TBytes; 
var 
    I, N: Integer; 
    P: PByte; 

begin 
    N:= CodeSize; 
    SetLength(Result, N); 
    P:= @Code; 
    for I:= 0 to N - 1 do begin 
    Result[I]:= P^; 
    Inc(P); 
    end; 
end; 
+0

Powinieneś napisać to tak, że istnieje tylko jedno wystąpienie bloku ASM –

+0

@DavidHeffernan - Dlaczego? – kludg

+0

Zawsze lepiej napisać raz, a nie dwa razy. Bardzo łatwe do zrobienia również. –

1

Na co warto, to bym uniknąć powielania odpowiedzi serg i napisać to tak:

function CodeToBytes: TBytes; 
var 
    StartAddr, EndAddr: Pointer; 
begin 
    asm 
    LEA EAX, @@start 
    MOV StartAddr, EAX 
    LEA EAX, @@end 
    MOV EndAddr, EAX 
    JMP @@end 
    @@start: 
    CALL EBX 
    @@end: 
    end; 
    SetLength(Result, Integer(EndAddr)-Integer(StartAddr)); 
    Move(StartAddr^, Pointer(Result)^, Length(Result)); 
end; 

Oczywiście można trzymać cokolwiek chcesz się między znacznikami początkowym i końcowym.

1

Wystarczy zastosować procedurę atrapę następujący kod i odjąć dwa, np:

procedure Code 
asm 
    call ebx; 
end; 

procedure CodeEnd; 
asm end; 

CodeSize := DWORD_PTR(@CodeEnd) - DWORD_PTR(@Code); 
CopyMemory(@MyByteArray[0], @Code, CodeSize); 

pamiętać, że w kodzie używać również użyć kodu Delphi zamiast ASM tak długo, jak nie nazywają się inny kod (funkcje/procedury/rtl)

EDYCJA: jako odpowiedź na komentarze Serga i Davida Heffernana zweryfikowałem wyniki z Delphi 2010 w trybie zwolnienia.

Użyłem poniższy kod:

procedure Code; 
asm 
    mov eax, 0; 
end; 

procedure CodeEnd; 
asm end; 


procedure TForm4.Button1Click(Sender: TObject); 
begin 
    ShowMessageFmt('CodeSize=%d', [DWORD_PTR(@CodeEnd) - DWORD_PTR(@Code)]); 
end; 

Podawane CodeSize jest 8 bajtów, to następnie weryfikowane za pomocą Ida Pro (dezasembler na wykonywalnego):

.text:004B3344     Code   proc near    
.text:004B3344               
.text:004B3344 B8 00 00 00 00     mov  eax, 0 
.text:004B3349 C3        retn 
.text:004B3349     Code   endp 
.text:004B3349 
.text:004B3349     ; ----------------------------- 
.text:004B334A 8B C0       align 4 

Więc w tym przykładzie mov eax , 0 to 5 bajtów (B8 00 00 00 00), retn (dodane przez kompilator) to 1 bajt (C3), wyrównanie 4 wynosi 2 bajty (8B C0), co daje łącznie 8.

+0

Nie jestem pewien, czy jest to bezpieczne, ponieważ kompilator może wyrównać punkt początkowy procedury dummy, dlatego użyłem funkcji 'CodeSize'. – kludg

+0

@Serg: Jeśli to wyrównanie (czy kompilator to robi? Nigdy nie widziałem), niż na pewno mam nadzieję, że kompilator wstawi NOP's :-) – Remko

+0

Well nop jest ok, ale nawet jeśli był to losowy bajt, to nie powinno mieć znaczenia, ponieważ kod procedury kończy się na retn – Remko