[Win32] Text uit een rich edit van een ander programma halen

Pagina: 1
Acties:

  • -DarkShadow-
  • Registratie: December 2001
  • Niet online
Ik heb programma X. Programma X heeft een rich edit waarin gegevens worden weergegeven. Deze gegevens zou ik graag willen loggen vanuit een door mij geschreven programma.

Nu moet ik dus de tekst die de rich edit weergeeft zien af te vangen.

Ik heb het al geprobeerd met GetDlgItemText(), deze stuurt een WM_GETTEXT message. Dit werkt prima op een static in hetzelfde venster, maar zeker niet op de rich edit.

Daarna heb ik het geprobeerd met een EM_GETTEXTEX message, want hier staat beschreven dat je daarmee de text uit een rich edit haalt. Dat heb ik geprobeerd met de volgende code:
C:
1
2
3
4
5
6
7
8
9
char * text_buffer = (char *) malloc(10000 * sizeof(char));
GETTEXTEX settings;
settings.cb = 10000 * sizeof(char);
settings.flags = GT_DEFAULT;
settings.codepage = CP_ACP;
settings.lpDefaultChar = NULL;
settings.lpUsedDefChar = NULL;
int text_length = SendMessage((HWND)adres,  (UINT) EM_GETTEXTEX, WPARAM)&settings,(LPARAM)text_buffer);
// text_length == 0 :(

Ook dit werkte niet, want zodra ik deze code uitvoer herstart programma X 8)7

Is er nog een manier om de tekst uit die rich edit te krijgen, of is bovenstaande manier nog aan de praat te krijgen?

BTW Programma X is uiteraard niet door mij geschreven.

Specialist in:
Soldeerstations
Oscilloscoop


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 16:58

.oisyn

Moderator Devschuur®

Demotivational Speaker

(jarig!)
Om dat te laten werken moet er gemarshalled worden; jij kunt niet zomaar een pointer naar een buffer in een ander proces aan die window geven, hij verwacht namelijk dat de buffer gewoon in z'n eigen adress space staat. Bij een normale WM_GETTEXT werkt dit meestal wel omdat windows voor een aantal messages zelf marshalling toepast.

Het kan wel, door geheugen te alloceren in dat proces, een pointer daarnaartoe te geven en daarna dat geheugen uit te lezen. VirtualAllocEx en ReadProcessMemory zijn de sleutelwoorden (uit mijn hoofd weliswaar). Bedenk dat je hier wel bepaalde rechten voor moet hebben.

[ Voor 6% gewijzigd door .oisyn op 02-03-2006 21:29 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Ricvdp
  • Registratie: Juni 2005
  • Laatst online: 17:44
Gaat dit niet verdacht veel op dll injectie lijken?

  • TheBlasphemer
  • Registratie: September 2004
  • Laatst online: 13-11-2025
Ricvdp schreef op donderdag 02 maart 2006 @ 21:33:
Gaat dit niet verdacht veel op dll injectie lijken?
Tuurlijk, maar Dll Injectie is heerlijk :D

Oki, even terug over dat marshalling, hier de stapjes (heb toevallig net nog ff nodig gehad ;))
Eerst moet je ProcessID weten van het process van het venster:
code:
1
2
        DWORD dwProcessID;
        DWORD dwThreadID=GetWindowThreadProcessId(hWindow,&dwProcessID);

hWindow is HWND van het venster, dwProcessID is process-id, dwThreadID is eigenlijk niet nodig, maar om het netjes te houden doen we dat maar wel ;)

Vervolgens gaan we het process openen met OpenProcess, voor het alloceren en schrijven naar geheugen hebben we de PROCESS_VM_WRITE en PROCESS_VM_OPERATION flags nodig.
code:
1
2
3
4
5
        HANDLE hProcess;
        if (hProcess=OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_WRITE|PROCESS_VM_OPERATION,false,dwProcessID)) {
...
CloseHandle(hProcess);
}

Mooi! nu hebben we een process waar we in kunnen fucken :D op de puntjes de rest van de code, die if en CloseHandle is lieve error handling ;) kun je evt nog een leuke else GeefFoutMelding() ofzo achter zetten :D

Oke, process open, nu willen we wat geheugenruimte hebben :)
Dit doen we met VirtualAllocEx. Lengte nemen we wel ff 1024 bytes. Let trouwens op dat je wel VirtualFreeEx anroept, anders ben je aant memory-leaken, en dat is niet netjes! je bent immers te gast in dat process :P
code:
1
2
3
4
5
void *pRemoteText=VirtualAllocEx(hProcess,NULL,1024,MEM_COMMIT,PAGE_READWRITE);
if (pRemotePath) {
...
VirtualFreeEx(hProcess,pRemoteText,1024,MEM_RELEASE);
}

Nu heb je dus een stukje geheugenruimte in dat andere process :D leuk he :)
Nu roep je die SendMessage met de pointer naar het geheugen in dat andere process, pRemoteText dus hier.

Maar we zijn nog niet klaar! die pointer zit in dat andere process, en die data dus ook :( en die willen we in ONS process hebben!
Nou kunnen we twee dingen doen:
1.Heel boos worden en gaan schoppen en slaan.
2.Netjes de data uitlezen met ReadProcessMemory :)
Dat laatste gaat zo:
code:
1
2
3
4
char szLocalText[1024];
if (ReadProcessMemory(hProcess,(void*)szLocalText,1024,NULL)) {
...
} else MessageBox(NULL,TEXT("De wereld vergaat! ReadProcessMemory vind me niet liev meer!"),TEXT("AAAARGH"),MB_OK);


Laat even weten of dit wel werkt :)
Trouwens, over welk Programma X hebben we het? Ik doe zelf ook nogal veel rondkloten met andere progsels, misschien heb ik (of iemand anders) er ook al eens wat mee gedaan :)

EDIT:
Besef me net dat je niet alleen een text nodig heb in dat process. In dat geval moet je dus even sizeof(GETTEXTEX) + ruimte voor string alloceren. en de pointer naar je string is dat pRemotePointer+sizeof(GETTEXTEX) :)
Voor het schrijven naar die remote data gebruik je WriteProcessMemory, werkt bijna identiek aan ReadProcessMemory, alleen de andere kant op. Op de een of andere manier zeikt WriteProcessMemory wel heel vaak als je NULL naar de laatste parameter gooit, dus gewoon ff een nutteloze DWORD aanmaken en pointer geven :)

[ Voor 11% gewijzigd door TheBlasphemer op 02-03-2006 22:00 ]

[img=http://www.web2messenger.com/smallstatus/w2m/theblasp.png]


  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 27-03 14:56
Misschien is het dan makkelijker om met AttachThreadInput jouw proces aan het externe te binden zodat je wel normaal bij de controls en het geheugen kan. Moet je aan het eind wel weer even netjes unbinden (met dezelfde functie alleen fAttach op false).

Weet niet zeker of het van toepassing is op dit probleem. Het verschaft je wel de mogelijkheid om dingen te benaderen waar je anders geen toegang voor hebt.

Hier staat ook nog iets over Rich Edit. Wat ik eruit opmaak is dat WM_GETTEXT (normaliter) wel zou moeten werken, maar als de text meer is dan 64k moet je EM_STREAMOUT of EM_GETSELTEXT gebruiken.

[ Voor 59% gewijzigd door riezebosch op 03-03-2006 09:51 ]

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 17-12-2025

curry684

left part of the evil twins

riezebosch schreef op vrijdag 03 maart 2006 @ 09:42:
Misschien is het dan makkelijker om met AttachThreadInput jouw proces aan het externe te binden zodat je wel normaal bij de controls en het geheugen kan. Moet je aan het eind wel weer even netjes unbinden (met dezelfde functie alleen fAttach op false).

Weet niet zeker of het van toepassing is op dit probleem. Het verschaft je wel de mogelijkheid om dingen te benaderen waar je anders geen toegang voor hebt.
Nee. AttachThreadInput koppelt enkel de message queues van verschillende GUI-threads binnen een en dezelfde process space. De scheiding tussen process spaces wordt door de MMU van de CPU bewaakt en genereert op hardware niveau de benodigde signals voor access violations indien overtreden. Je zal dus via het OS toegang tot de process space van de andere applicatie moeten verzoeken.

Professionele website nodig?


  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 27-03 14:56
Weet je dat zeker? Ikzelf heb het gebruikt om de focus van het control in een andere process space op te vragen, zoals ook bij GetFocus uitgelegd staat:
Use the GetForegroundWindow function to retrieve the handle to the window with which the user is currently working. You can associate your thread's message queue with the windows owned by another thread by using the AttachThreadInput function.

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 16:58

.oisyn

Moderator Devschuur®

Demotivational Speaker

(jarig!)
riezebosch: het doet precies wat daar staat, maar het mapt niet de address space van het ene proces in het andere. Je moet een pointer opgeven naar een buffer waar de text in komt te staan; de buffer leeft in jouw proces maar degene die de copy doet (de windowproc van die rich text window) gebruikt de proces space van de ander. De pointer die jij geeft heeft dus niets te maken met jouw eigen buffer maar wijst gewoon naar dezelfde plek in het andere proces.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • -DarkShadow-
  • Registratie: December 2001
  • Niet online
_/-\o_ _/-\o_ _/-\o_ Wow, bedankt voor deze reuze handige en behulpzame post :)

Ik heb met behulp van de aanwijzingen van TheBlasphemer even een testprogrammaatje geschreven:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    /* initialisatie */
    DWORD nutteloos; // :)
    DWORD dwProcessID = 0x00000348;
    HWND hWindow = (HWND) 0x000F063C;
    HWND hControl = (HWND) 0x001A06F8;
    int BufferSize = 1024;
    int MemSize = BufferSize + sizeof(GETTEXTEX);
    char LocalBuffer[1024];

    GETTEXTEX SrTex;
    SrTex.cb = BufferSize;
    SrTex.flags = GT_DEFAULT; SrTex.codepage = CP_ACP; SrTex.lpDefaultChar = NULL; SrTex.lpUsedDefChar = NULL;

    DWORD dwThreadID = GetWindowThreadProcessId(hWindow, &dwProcessID);

    HANDLE hProcess;
    if(hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, false, dwProcessID)){
        void * pRemoteText = VirtualAllocEx(hProcess, NULL, MemSize, MEM_COMMIT, PAGE_READWRITE);

        if(pRemoteText){
            if(WriteProcessMemory(hProcess, pRemoteText, &SrTex, sizeof(GETTEXTEX), &nutteloos)){
            
                int text_length = SendMessage(hControl, EM_GETTEXTEX, (WPARAM)pRemoteText, (LPARAM)pRemoteText + sizeof(GETTEXTEX));
            
                /* --> text_length == 0 */

                if(ReadProcessMemory(hProcess, pRemoteText, LocalBuffer, BufferSize, NULL)){
                /* --> ^^^^ Problematische regel */
                    printf("%s", LocalBuffer);
                }
                else{
                    printf("ERROR: Could not read memory of process :(\n");
                }
            }
            else{
                printf("ERROR: Could not write to process memory :(\n");
            }
            VirtualFreeEx(hProcess, pRemoteText, MemSize, MEM_RELEASE);
        }
        else{
            printf("ERROR: Can't allocate any memory in process.\n");
        }
        CloseHandle(hProcess);
    }
    else{
        printf("ERROR: Can't open process with ID: %X\n", dwProcessID);
    }

    printf("ProcessID of window with handle %X is: %X\n",hWindow, dwThreadID);


Het programma doet (volgens mij) exact hetgene dat TheBlasphemer bedoelt. Helaas werkt het nog niet. Door mijn uitgebreide (maar vieze) error handling heb ik het probleem gevonden.

De ReadProcessMemory functie op regel 27 returnt 0, hij doet het dus niet. Hij geeft als error Acces Denied. Ik heb geen idee waarom, hetzelfde geheugen alloceren en beschrijven werkt wel :?

Met &nutteloos i.p.v. NULL als laatste argument werkt ReadProcessMemory ook niet.

pRemoteText moet daar eigenlijk pRemoteText + sizeof(GETTEXTEX) zijn, maar daar kan de compiler niet mee leven. Daarom heb ik de functie getest met enkel pRemoteText, daarmee zou de functie immers ook moeten werken.

Wanneer ik pRemoteText + sizeof(GETTEXTEX) gebruik geeft de compiler de volgende error:
"error C2036: 'void *' : unknown size"

SendMessage returnt nog steeds 0, terwijl de Rich Edit zeker niet leeg is.

Hoe krijg ik dit aan de praat?

[ Voor 8% gewijzigd door -DarkShadow- op 03-03-2006 23:47 ]

Specialist in:
Soldeerstations
Oscilloscoop


  • TheBlasphemer
  • Registratie: September 2004
  • Laatst online: 13-11-2025
Hoe je dit aan de praat krijgt kunnen we (of in ieder geval ik ;)) je niet vertellen. Dan moet je toch meer vertellen over het programma zodat we zelf ook even aan kunnen kloten :P
Wat ik persoonlijk zou doen is eerst eens kijken of je EM_GETTEXTLENGTHEX wel aan de praat krijgt, en of je daarmee wel een goede lengte krijgt.

Ik heb even gepoogd je via MSN toe te voegen, om je zo misschien sneller te kunnen helpen, maar je blijkt niet online te zijn ;) (Tsja, wat wil je om 1 uur snachts :P). Als je morgen dus berichtje krijgt dat ene "FW" je heeft toegevoegd, that's me :)

offtopic:
En vertel nou godver is wat programma X is :P wordt er helemaal neurotisch van als ik niet zelf kan testen ;)

[img=http://www.web2messenger.com/smallstatus/w2m/theblasp.png]


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
TheBlasphemer schreef op zaterdag 04 maart 2006 @ 00:55:
Ik heb even gepoogd je via MSN toe te voegen, om je zo misschien sneller te kunnen helpen, maar je blijkt niet online te zijn ;) (Tsja, wat wil je om 1 uur snachts :P). Als je morgen dus berichtje krijgt dat ene "FW" je heeft toegevoegd, that's me :)
offtopic:
De me een lol en bespreek / help in dit topic. Zo leren andere mensen er ook nog iets van en wordt de "GoT-knowledgebase" weer eens lekker gevuld met zinnig gezwam ;)

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • TheBlasphemer
  • Registratie: September 2004
  • Laatst online: 13-11-2025
RobIII schreef op zaterdag 04 maart 2006 @ 01:25:
[...]

offtopic:
De me een lol en bespreek / help in dit topic. Zo leren andere mensen er ook nog iets van en wordt de "GoT-knowledgebase" weer eens lekker gevuld met zinnig gezwam ;)
Tuurlijk is het wel de bedoeling dat de oplossing op GoT komt, maar het gaat gewoon een stukje sneller over MSN, aangezien je anders maar moet hopen dat de ander net GoT leest ;)

[img=http://www.web2messenger.com/smallstatus/w2m/theblasp.png]


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
TheBlasphemer schreef op zaterdag 04 maart 2006 @ 01:26:
[...]


Tuurlijk is het wel de bedoeling dat de oplossing op GoT komt, maar het gaat gewoon een stukje sneller over MSN, aangezien je anders maar moet hopen dat de ander net GoT leest ;)
offtopic:
Ik begrijp je, en vind het heel nobel dat je zo wil helpen, maar ook de weg naar de oplossing kan voor anderen interessant en leerzaam zijn. Zeker omdat er, tijdens het "puzzelen", nogal eens wat fouten worden gemaakt c.q. verkeerde afslagen worden genomen die ook leerzaam zijn voor anderen.

[ Voor 6% gewijzigd door RobIII op 04-03-2006 01:29 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • -DarkShadow-
  • Registratie: December 2001
  • Niet online
Ik ben er bijna :)

ReadProcessMemory werkte niet omdat ik bij OpenProcess geen VM read access aanvroeg. Zo moet het wel:
C:
1
hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_VM_READ, false, dwProcessID)


SendMessage() returnt nog steeds 0, maar dat zal wel komen doordat de ontvanger van het bericht in een ander proces bezig is. De buffer wordt namelijk wel gevult met de juiste tekst :)

Dus ik zit alleen nog maar met een C probleem:
C:
1
ReadProcessMemory(hProcess, pRemoteText, LocalBuffer, BufferSize, NULL)

pRemoteText zou hier dus pRemoteText + sizeof(GETTEXTEX) moeten zijn. Op regel 23 doe ik exact hetzelfde en daar werkt het gewoon.

Microsoft zegt er dit over, maar daar los ik het niet mee op.

Specialist in:
Soldeerstations
Oscilloscoop


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 16:58

.oisyn

Moderator Devschuur®

Demotivational Speaker

(jarig!)
pRemoteText is een void pointer. Een void heeft geen grootte, het is in feite een uncomplete type. De grootte van het element waarnaar gepoint wordt moet bekend zijn om pointerarithmetic op toe te passen. Als je bijvoorbeeld 1 bij een int pointer optelt, dan wijst de pointer daarna 4 bytes verder, omdat de grootte van een int 4 bytes is (op het door jouw gebruikte platform). Maar een void heeft geen pointer, en aangezien je gewoon bytes erbij wilt tellen is het dus handig om de pointer eerst te casten naar een char*, zodat je er daarna wel pointerarithmetic op los kunt laten.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1