Log in

View Full Version : IDA SDK - Writing a PlugIn used during debugging


Lehona
August 23rd, 2011, 17:39
I'm quite new to the IDA SDK (To be honest, this is my first project) and I have encountered some problems and questions:
The PlugIn is specific to one program (Gothic2 if anyone knows that game) and will be used during creating modifications, helping the modder to debug with more ease.
Actually I want to print out some data in the RAM of the debugged process (Giving out some variables' data). To find them by name I have to search through a table and since Piranha Bytes, who created Gothic, made their own strings (zStrings) which don't always end with a nullbyte since they hold their length as a member, I had some struggle to cast them to normal char* when wanting to read them. This is the class (Can't modify it since it's internal representation):

Code:
class zString {
public:
int _vtbl;
int _allocater;
private:
char* ptr; //not always ending with a nullbyte therefore private
public:
int len; //Length
int res; //amount of allocated memory (bytes)

zString() {};

zString(int zstrptr) { // This does copy the string!
dbg->read_memory(zstrptr, this, sizeof(zString));
}

char* getStr() { // You gotta free those after use!
char* mem = (char*)qcalloc(len+1, 1);
dbg->read_memory((ea_t)this->ptr, mem, len)
return mem;
}

};


the getStr()-method kinda seems to fail, if I print 'mem' it just turns out to be an empty string. Do you any thing which could be wrong? I'm still always unsure when dealing with "normal" memory and the dbg-memory.

With best regards, Lehona

Kayaker
August 24th, 2011, 00:40
Hi

Maybe you've already checked this, but what is the return value of read_memory? I believe it should be the number of bytes read if successful, -1 or 0 if error (see your copy of idd.hpp for the current details for read_memory). This should at least give some feedback about the problem.

I just noticed..is it a typo that there is no semicolon at the end of the dbg->read_memory statement?

Lehona
August 24th, 2011, 10:45
Edit: Okay, ignore me. It's just impossible to use the point-operator to refer to dbg-memory. Got alot further, I'll post if I need more help. Thanks anyways!


Thanks for the reply!

I tested it for zero and it didn't show the debug messages, but since I suspected to vftbl to fail (I don't create the zString at all, it's already in the memory), I completely removed the method and made it a function, now at least general debug messages are shown and read_memory() returns 0. Do you know why this fails? The address I try to read is not even in the code-section (Although this shouldn't be a problem anyways) and is read by the programm itself many times.


Just in case you want to help my out even further (not just predicting why read_memory() returns 0), here's the actual code I use:


public:
zString name; //0x0000 zSTRING //Name des Symbols, so wie im Script

int next; //0x0014 zCPar_Symbol* //Scheinbar sind die Symbole verkettet. Erscheint mir nutzlos, es gibt ja die Symboltabelle.

//Inhalt des Symbols, Pointer oder Primitiver Typ
int content; //0x0018 void* oder int* oder float* oder zSTRING* oder int oder float. Bei Funktionen / Instanzen / Prototypen: Stackpointer. Sonst Daten oder Datenpointer.
int offset; //0x001C Offset bei Klassenvariablen // Adresse bei Instanzen // Rückgabewert bei Funktionen

int bitfield; //0x0020 siehe oben
int filenr; //0x0024
int line; //0x0028
int line_anz; //0x002C
int pos_beg; //0x0030
int pos_anz; //0x0034

int parent; //0x0038 zCPar_Symbol* // Parent-Verweis

};
char* getStr(char* ptr, int len) { // You gotta free those after use!
msg("here";
char* mem = (char*)qcalloc(len+1, 1);
int i = dbg->read_memory((ea_t)ptr, mem, len);
msg ("%d", i);
return mem;
}




int contentSymbolTableAddress;
int currSortedSymbolTableAddress;
int currSymbolTableAddress;
int currSymbolTableLength;

zCPar_Symbol* GetParserSymbol(char *inst) {
// Some parser constants
const int ContentParserAddress = 0xAB40C0;
const int zCParser_symtab_table_array_offset = 0x18;
const int zCParser_sorted_symtab_table_array_offset = 0x24;

// Init some parser addresses
dbg->read_memory((ea_t)ContentParserAddress + zCParser_symtab_table_array_offset, &contentSymbolTableAddress, sizeof(void*));
dbg->read_memory((ea_t)ContentParserAddress + zCParser_sorted_symtab_table_array_offset, &currSortedSymbolTableAddress, sizeof(void*));
dbg->read_memory ((ea_t)ContentParserAddress + zCParser_symtab_table_array_offset, &currSymbolTableAddress, sizeof(void*));
dbg->read_memory((ea_t)ContentParserAddress + zCParser_symtab_table_array_offset + 8, &currSymbolTableLength, sizeof(void*));
msg("Front of loop";
for (int i = 0; i < currSymbolTableLength; i++) {
zCPar_Symbol* symb;
dbg->read_memory((ea_t)currSymbolTableAddress+(i*4), &symb, sizeof(zCPar_Symbol*));
msg("Symbol read, %d", i);
char* str = getStr(symb->name.ptr, symb->name.len);
msg("got string, %s", str);
if (strcmp(inst, str)==0) {
qfree(str);
msg("str cmp succ";
return symb;
};
msg("str cmp";
qfree(str);
};


return NULL;
};

void IDAP_run(int arg)
{
// The "meat" of your plug-in
if (!is_debugger_on()) {
msg("Debugger is not running, no runtime-memory exists\n";
return;
} else {
msg("Debugger is running!\n";
};

// Ask for the symbolname
va_list va;
char inst[MAXSTR];
callui(ui_asktext, 50, inst, NULL, "Enter symbolname", va);
zCPar_Symbol *symb;
symb = GetParserSymbol(inst);
if (symb == NULL) {
msg("VAR NOT FOUND";
return;
};
msg("Name: %s \n Content: %d \n Offset: %d \n Bitfield: %d \n", getStr(symb->name.ptr, symb->name.len), symb->content, symb->offset, symb->bitfield, va);
};


It generates this output:
Debugger is running!
Front of loop Symbol read, 0 here0got string, str cmp
Symbol read, 1 here0got string, str cmp
Symbol read, 2 here0got string, str cmp
Symbol read, 3 here0got string, str cmp
Symbol read, 4 here0got string, str cmp
Symbol read, 5 here0got string, str cmp
Symbol read, 6 here0got string, str cmp
Symbol read, 7 here0got string, str cmp
Symbol read, 8 here0got string, str cmp
Symbol read, 9 here0got string, str cmp
Symbol read, 10 here0got string, str cmp
Symbol read, 11 here0got string, str cmp
Symbol read, 12 here0got string, str cmp
Symbol read, 13 here0got string, str cmp
Symbol read, 14 here0got string, str cmp
Symbol read, 15 here0got string, str cmp
Symbol read, 16 here0got string, str cmp
Symbol read, 17 here0got string, str cmp
Symbol read, 18 here0got string, str cmp
Symbol read, 19 here0got string, str cmp
Symbol read, 20 here0got string, str cmp
Symbol read, 21 here0got string, str cmp
Symbol read, 22 here0got string, str cmp
Symbol read, 23 here0got string, str cmp
Symbol read, 24 here0got string, str cmp
Symbol read, 25 here0got string, str cmp
Symbol read, 26 here0got string, str cmp
Symbol read, 27 here0got string, str cmp
Symbol read, 28 here0got string, str cmp
Symbol read, 29 here0got string, str cmp
Symbol read, 30 here0got string, str cmp
Symbol read, 31 here0got string, str cmp
Symbol read, 32 here0got string, str cmp
Symbol read, 33 here0got string, str cmp
Symbol read, 34 here0got string, str cmp
Symbol read, 35 here0got string, str cmp
Symbol read, 36 here0got string, str cmp
Symbol read, 37 here0got string, str cmp
Symbol read, 38 here0got string, str cmp
Symbol read, 39 here0got string, str cmp
Symbol read, 40 here0got string, str cmp
Symbol read, 41 here0got string, str cmp
Symbol read, 42 here0got string, str cmp
Symbol read, 43 here0got string, str cmp
Symbol read, 44


After this, it gives me an Access Violation.

Gothic uses SmartHeap.dll, in case this might be important.