Pokaż wyniki 1 do 7 z 7

Temat: c + asm

  1. #1

    Domyślnie c + asm

    mam program ktory zaklada hokoa na inny.
    sa funkcje (virtualprotect, virtualalloc, writememory), oraz kod hooka. Wszsytko w asmie wyglada prosto.

    Ale nie zawsze chce mi sie pisac wszystkiego w asmie.
    Czesc zakladajaca hooka w c, czesc jego obslugi w asmie. Jak to polaczyc?
    Chodzi o WriteProcessMemory, jak podac mu bufor, oraz wielkosc kodu w asmie?
    no i jak w c napisac jakis kod w asmie:


    int main(){
    WriteProcessMemory(kod w asmie, sizeof(kod w asmie));
    /*kod w asmie*/
    }


    oczywiscie chce miec mozliwosc tworzenia labeli (to relatywnych skokow), oraz edycji opcodow przy ladelach (adres powrotu z funkcji, 0x00 0x00 0x00 0x00 na poczatku)

  2. #2
    Zarejestrowany
    Oct 2008
    Skąd
    W Sieci !!!
    Postów
    282

    Domyślnie

    Ogólnie chcesz zrobic w C++ wstawke asma ? Bo nie wiem czy dobrze Cie rozumie.

    Jesli tak to pamietaj ze jak zmieniasz C++ na asemblera zmienna nie istnieje. Zostanie tylko to co bylo zmienna w c++.
    Musisz wywołac funkcje wołającą ;P Jakoś tak.

    Dosyć pirdolenia Sprawdz tak :

    asm{
    /*instrukcje w asemblerze*/
    }

    np:

    asm{
    cośtam.x2
    int 10h
    }

    Pierwszy nawias klamrowy musisz miec w tej samej linii co słowo kluczowe.

    Lama nie jesteś :P

    przyklad :

    asm
    {
    //instrukcje w asemblerze
    }

    Nie raz może nie podziałać to wpisz tak ;

    Przykład :

    asm{
    //instrukcje w asemblerze
    }

    Jak znowu nie podziała no to ta :

    asm ("instrukcja");

    A poniżej przepisałem Ci fragment książki którą Tobie też polecam

    Oprócz pisania kodu w czystym asemblerze, przydatne okazuje się wstawianie fragmentów programu, zapisanych w asemblerze, do źródła programu, pisanego w języku wysokiego poziomu, np. C. GCC umożliwia kompilowanie plików źródłowych języka C ze wstawkami w asemblerze (ze składnią AT&T). Ogólna forma wstawek asemblerowych jest wspólna dla różnych platform, ale więzy argumentów maja różne znaczenie dla różnych platform sprzętowych. Tutaj omawiany będzie wariant w architekturze x86 Intela.

    Wstawki asemblerowe można pisać w sposób zupełnie bezpośredni, po prostu pisząc kod jaki chcemy wykonać:

    __asm__ (" movl $1, %eax
    movl $0, %ebx
    int $0x80");

    Jeżeli użycie asemblera sprowadza się do takiego wywołania jak wyżej to taka forma może wystarczać. Ale asembler w GCC pozwala zapisać skrótowo pewne operacje, które zostaną automatycznie rozwinięte do odpowiednich instrukcji asemblerowych.
    Jest możliwe określenie danych, które zostaną użyte jako wejście i wyjście instrukcji asemblerowych oraz rejestry, które zostaną zmodyfikowane. Każdy argument może być opisany przez typ (więzy) oraz wyrażenie ze świata języka C w nawiasach. Wyrażenia w części output muszą być "l-wartościami" (kompilator może to sprawdzać), bo na te wartości będzie dokonywany zapis.
    Manual do GCC twierdzi, że instrukcje asemblerowe wewnątrz szablonu nie są w żaden sposób parsowane i sprawdzane przez kompilator zatem nie będzie sprawdzone czy instrukcja jest poprawną instrukcją dla asemblera danego procesora, czy ma poprawną liczbę argumentów itd. Natomiast praktyka wykazuje coś zupełnie przeciwnego, czyli nie dość, że instrukcje są sprawdzane to również sprawdzana jest poprawność argumentów.
    Najczęstszym sposobem dostawania się do zdefiniowanych w szablonie argumentów jest używanie ich numeracji w kolejności, tj. %0 dla pierwszego argumentu, %1 dla drugiego itd.
    Przykład:
    int a;
    int b = 10;
    int c = 20;
    __asm__ (" mov %2, %0"
    : "=a"(a)
    : "0" (b), "c" (c)
    );

    Powyższy przykład wymaga kilku wyjaśnień. Jak zostało wspomniane wyżej, po instrukcji występuje opis wyjścia, wejścia i modyfikowanych rejestrów. Części te oddzielane są dwukropkami, zatem instrukcja jest postaci: __asm__ ("instrukcje" : output : input : modify);. Jeżeli chcemy pominąć sekcję output, to należy pozostawić puste miejsce po pierwszym dwukropku (dobrze jest zaznaczyć komentarzem, że celowo nic tam nie zostało umieszczone). Modify również jest opcjonalne. Argumenty do zapisu muszą być poprzedzone znakiem "=".
    Typy (więzy) argumentów, o których wspomniane jest wyżej są określane literami w cudzysłowie. Tutaj dochodzimy do części związanej ze sprzętem. Część typów jest wspólna dla wszystkich platform, natomiast wiele z nich jest specyficznych dla konkretnych architektur, a wynika to chociażby z tego, że na różnych architekturach nazewnictwo i liczba rejestrów jest zupełnie inne. Do wspólnych więzów należą:
    m dostęp do pamięci
    0, 1, ... oznaczenie argumentu, który już występuje na liście argumentów
    i bezpośrednia wartość
    r jakiś rejestr ogólny

    Podstawowe więzy specyficzne dla architektury Intela:
    a, b, c, d, D, S odpowiednio rejestry eax, ebx, ecx, edx, edi, esi
    q jeden z rejestrów eax, ebx, ecx, edx

    Wszystkich więzów jest znacznie więcej i do ciekawszych zastosowań warto zapoznać się z pełną listą zawartą w manualu do GCC.
    Zamiast numerów wejść/wyjść można podawać bezpośrednio nazwę rejestru, którego chce się używać, ale wtedy należy go poprzedzić dwoma znakami "%", na przykład:

    __asm__ ("xorl %%ebx, %%ebx", : : "b" (b));

    Warto obejrzeć do czego rzeczywiście rozwijane są nasze przykładowe szablony. Znany już program:
    int a;
    int b = 10;
    int c = 20;
    __asm__ (" mov %2, %0"
    : "=a" (a)
    : "0" (b), "c" (c)
    );

    Kompiluje się do czegoś zbliżonego:

    1. movl -8(%ebp),%eax
    2. movl -12(%ebp),%ecx
    3. movl %ecx, %eax
    4. movl %eax,%edx
    5. movl %edx,-4(%ebp)

    1., 2. - wartości zmiennych zdeklarowanych wyżej są wrzucane do rejestrów eax i ecx, co wynika z wiersza : "0" (b), "c" (c), który żąda zapisania do rejestru ecx ("c") wartości zmiennej c, natomiast zapis "0" (b) żąda zapisania wartości zmiennej b do rejestru wskazywanego przez typ podany jako pierwszy czyli rejestr eax ("=a").
    3. - instrukcja mov %2, %0 z podstawionymi odpowiednimi parametrami, zatem na pierwszy parametr podstawiony jest typ podany jako trzeci ("c") czyli %eax, a na drugi - typ podany jako pierwszy ("=a") czyli eax.
    W wierszu : "=a" (a) zażądaliśmy zapisania, po wykonaniu kodu, zawartości rejestru eax do zmienej a, co realizują instrukcje 4.-5.

    Warto również wiedzieć, że kompilator sprawdza rozmiar typu podanego w nawiasach i na podstawie tej informacji generuje odpowiedni rejestr, czyli gdyby zamiast int w programie zapisać zmienne typu char i zamiast instrukcji movl zapisać instrukcję movb to kompilator zapisałby program jako:

    movb -2(%ebp),%al
    movb -3(%ebp),%cl
    movb %cl, %al
    movb %al,%dl
    movb %dl,-1(%ebp)

    Widać, że zostały użyte rejestry rozmiaru jednego bajtu.
    Na koniec jeszcze krótki przykład użycia typu "m" czyli odnoszącego się do pamięci. Jasne jest, że instrukcja:

    __asm__ ("movl %0, %1" : : "a"(b), "b"(c));

    rozwinie się do:

    movl -8(%ebp),%eax
    movl -12(%ebp),%ebx
    movl %eax, %ebx

    Czyli wartości zmiennych zostaną zapisane do rejestrów eax i ebx, na których następnie zostanie wykonana operacja mov.
    Do czego natomiast rozwinie się kod jeżeli zażądamy korzystania bezpośrednio ze zmiennej w pamięci? Następujący kod:

    __asm__ ("movl %0, %1" : : "a"(b), "m"(c));

    rozwinie się do:

    movl -8(%ebp),%eax
    movl %eax, -12(%ebp)

    Czyli zostanie wykonana bezpośrednia operacja na pamięci. Pozornie drugi zapis wygląda na lepszy, bo zapis jest krótszy, ale często nie da się wykonać operacji bezpośrednio na komórkach pamięci (chociażby w powyższy przykład nie skompiluje się, jeżeli również w pierwszym typie podalibyśmy "m"), a także ze względów wydajnościowych takie rozwiazanie może okazać się gorsze (nieraz instrukcje działają na komórkach pamięci znacznie wolniej niż na rejestrach).


    Tytuł książki :

    Asembler w kodzie Linuksa autorów
    Krzyska Szatyńskiego i Andrzeja Kuracha...
    "Wszystkie komputery PC są kompatybilne, ale niektóre są kompatybilniejsze od innych... Twój jest zawsze mniej kompatybilny..."

  3. #3

    Domyślnie Wskaźnik

    Witam,
    -wie może ktoś jak zrobić wskaźnik w "dev c++" to pojedynczych komórek pamięci?
    -np.: string *a = 0x33333; cout<<*a;
    -bo opcja z numerycznym przypisaniem wywołuje błędy, nie wiem czy dev'ie się to robi trochę inaczej, a może jest jakaś standardowa funkcja?
    -ogólnie chodzi mi żeby nadać adres wskaźnikowi, a potem odczytać jako string wszystko do NULL (czyli bajtu zerowego)


    Pozdrawiam

  4. #4

    Domyślnie

    skracając odp mandr4ka dodam jeszcze to:

    --------C---------
    asm{
    mov AX,10h dla pojedynczej instrukcji można robić <asm je Label>
    int 10h
    }
    --------C++------
    _asm{
    mov AX,10h
    int 10h
    }

    Natomiast wymiana zmiennych zachodzi płynnie:


    #include<stdio.h>

    main()
    {
    int bufor;
    int cAX;
    asm EAX,bufor
    asm cAX,AX
    printf("Zawartość AX:%d",cAX);
    return 0;
    }
    Ostatnio edytowane przez Elitegroup : 01-15-2009 - 12:24

  5. #5
    Zarejestrowany
    Oct 2008
    Skąd
    W Sieci !!!
    Postów
    282

    Domyślnie

    Słuszna racja :>



    grupalokalna podstawy podstawy
    "Wszystkie komputery PC są kompatybilne, ale niektóre są kompatybilniejsze od innych... Twój jest zawsze mniej kompatybilny..."

  6. #6

    Domyślnie

    grupalokalna a cout<<*a[0] nie działa ?

  7. #7
    Zarejestrowany
    Jan 2009
    Skąd
    /tmp
    Postów
    30

    Domyślnie

    Kod:
     wskaznik = reinterpret_cast<int *> (adres_numeryczny)
    W ten sposob ustawisz wskaznik na adres, ktory jest liczba calkowita w C++.

    Pozdro.
    " Wszystko, co ma początek, ma też koniec. Widzę nadchodzący koniec. Widzę rozciągającą się ciemność. Widzę śmierć ."

Podobne wątki

  1. asm - wady i zalety
    By GSG-9 in forum Assembler
    Odpowiedzi: 9
    Autor: 01-13-2009, 21:19

Zasady Postowania

  • Nie możesz zakładać nowych tematów
  • Nie możesz pisać wiadomości
  • Nie możesz dodawać załączników
  • Nie możesz edytować swoich postów
  •  
Subskrybuj