Пач по време на изпълнение в C++/inline асемблиране

Опитвам се да коригирам функцията cat(), за да върне true, но по някаква причина програмата се срива, когато дори не извикам функцията. Дали проблемът е моят метод за корекция? Мисля, че пиша на правилния адрес (адресът на функцията е 004012e4). Използвам кодови блокове (gcc) на 32-битова система с Windows XP.

#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;

int cat()
{
    cout<<"false"<<endl;
    return false;
}

int main()
{
    DWORD beef;
    int (*css)();
    css=cat;
    cout<<css<<endl;
    system("PAUSE");
    VirtualProtect(&css,49,PAGE_EXECUTE_READWRITE,&beef);
    asm("mov $0x40130f,%eax");//move address of the mov $0x0,eax instruction to eax
    asm("movl $0x1,(%eax)");//write at address changing B800 to B801 or return true

    return 0;
}

person Jordan    schedule 06.12.2012    source източник
comment
Заглавието вече е удебелено и с увеличен размер на шрифта - няма нужда от главни букви.   -  person    schedule 06.12.2012
comment
Сигурни ли сте, че адресът на LSB на непосредствения операнд е 0x40130f?   -  person chill    schedule 06.12.2012
comment
Какво връща VirtualProtect (може да се провали)? Сигурни ли сте, че пишете на правилния адрес във функцията (внимавайте за обвивката на функцията)? Не съм сигурен дали кодът ви за корекция е грешен, но определено не е както обикновено правя това (може би трябва да бъде css = &cat и по-късно memcpy(asmBuffer, css)).   -  person ssube    schedule 06.12.2012
comment
VirtualProtect връща 1, което показва успех   -  person Jordan    schedule 06.12.2012
comment
peachykeen какво е asmBuffer?   -  person Jordan    schedule 06.12.2012
comment
Трябва да посочите (void*)css вместо &css за VirtualProtect. Можете да направите това, като поставите css и void * в обединение, след което посочите void * члена. Освен ако не съм срещал компилатори с грешки, css може да е „просто указател“.   -  person ActiveTrayPrntrTagDataStrDrvr    schedule 07.12.2012


Отговори (2)


Защо кодирате твърдо адреса на функцията? Имате го в код, разпечатвате го. Ако го отпечатате и след това промените кода, за да включи това, което сте отпечатали, рискувате да преместите функцията. Защо просто не генерирате динамично израза за асемблиране?

person AShelly    schedule 06.12.2012
comment
Много се съмнявам, че това ще проработи... 'sprintf' ще се изпълни по време на изпълнение, а 'asm' е просто директива към gcc за включване на асемблерния код в генерирания код. Което по време на изпълнение вече е генерирано. - person Nik Bougalis; 07.12.2012
comment
@nik, мисля, че си прав. Изглежда, че няколко месеца програмиране на пълен работен ден на динамичен език са повредили моя вътрешен C стек. - person AShelly; 07.12.2012

Не съм 100% в това, но съм почти сигурен, че кодовият сегмент не е съпоставен със селектора на данни. Сегментът на селектора на данни по подразбиране в x86 CPU се нарича ds, но кодът е в регистъра на селектора cs. От съображения за безопасност (а вероятно и поради причини за пространството на виртуалната памет) вярвам, че кодът обикновено не се картографира към същото пространство.

Не съм запознат с GCC asm, но нещо подобно може да свърши работа:

asm("mov $0x40130f,%eax");
asm("push %%fs");
asm("mov %%cs,%%fs");   // Not sure you can address memory using cs:eax directly...
asm("movl $0x1,%%fs:(%eax)");
asm("pop %%fs");

Мина много време, откакто писах асемблер, но вероятно разбирате какво имам предвид.

person Jonas Byström    schedule 06.12.2012
comment
Gcc казва, че инструкциите (mov%cs,%fs) и (movl $0x1,(%fs:%eax)) са невалидни - person Jordan; 07.12.2012
comment
След бързо търсене открих, че регистрите на селектора използват знаци за двоен процент и трябва да са извън отместването, когато се комбинират в дълъг адрес; отговорът се актуализира съответно. За протокола също искам да отбележа, че GCC asm синтаксисът е гаден. - person Jonas Byström; 07.12.2012
comment
И cs, и ds са картографирани към цялото линейно адресно пространство в x86 (т.е. те не използват сегментиране) - person szx; 07.12.2012
comment
@szx: това означава ли, че ще имат същите права? Спомням си, че можете да имате различни права за достъп на различни селектори и съм сигурен, че сегментите от данни нямат права за достъп за изпълнение и съм сигурен, че по подразбиране обратното е вярно (но може би VirtualProtect се справя с това). - person Jonas Byström; 07.12.2012
comment
@JonasByström: правата за достъп се управляват чрез пейджинг (виртуална памет) - person szx; 07.12.2012
comment
@szx: също се обработва от пейджинг. Не само обаче. x86 има две ограничения за защита в защитен режим за достъп до паметта: селектори и страници. Пейджингът обаче няма ограничения за сигурност за данните, така че те не могат да използват едни и същи селектори, или ще можете да изпълните самопроменящ се код, без да прескачате през обръчите. Също така бихте могли да създадете съответно грешки, когато случайно прескочите в данни. Което не можете (по подразбиране). - person Jonas Byström; 07.12.2012
comment
@JonasByström: Е, в съвременните операционни системи (включително Windows и Linux) сегментирането почти не се използва - сегментите на кода, данните и стека напълно се припокриват, обхващайки от 00000000 до FFFFFFFF и имат еднакви права за достъп. Това са таблици/директории на страници, които управляват достъпа за четене/запис за отделни страници или набори от страници. - person szx; 07.12.2012
comment
@szx: Прав си, грешах! Това, мога да ви уверя, не работеше по мое време: int x=0xC3; typedef void (*P)(); P p = (P)&x; p();, но току-що го опитах и ​​със сигурност работи на Windows XP Home сега. Благодаря! :-) - person Jonas Byström; 08.12.2012
comment
Добре по някаква причина gcc казва само asm(mov %%cs,%%fs); има невалидни операнди - person Jordan; 08.12.2012