Log in

View Full Version : symbol not defined - Why?


5aLIVE
December 21st, 2003, 15:08
Hi this is my first post to this excellent reversing resource.
I have a Delphi app I am hoping to patch.
I have loaded the app into IDA Pro to create a MAP file and have tried DeDe too. I loaded converted a .DCU file to a DSF file and loaded the newly created DSF file. I then created and export MAP file.

I manually created .SYM and .NMS files in DOS (Dede didn't detect my SICE - DS3 w/ XP SP1 - no tricks) and loaded them into Soft Ice symbol loader, these were translated and loaded sucessfully.

Typing SYM in SICE shows Dialogs::ShowMessage(System::AnsiString),
which is the name of the Delphi function I want to set a BP for (it is used to handle strings read from a separate file to be displayed in a message box).

After attaching to the app and typing:
BPX ShowMessage, or
BPX Dialogs::ShowMessage(System::AnsiString)

Gives the "symbol not defined message"

Can someone tell me where I'm going wrong?

dELTA
December 21st, 2003, 20:02
The best and easiest tool for converting IDA symbols to Softice symbols is Mostek's IDA to Softice plugin, you can find it at:

hxxp://mostek.subcultural.com

Try that one and see if it works any better.

Aimless
December 22nd, 2003, 00:54
Simple thing to remember is when name is complicated, you use quotes around it. Therefore, you should try:

bpx "Dialogs::ShowMessage(System::AnsiString)"

If that does not work:

1. Open your map file
2. Select the function (it'll be in the format of <addr> <name> where <name> will be your [Dialogs::ShowMessage(System::AnsiString)]
3. Rename the function to say: MyHack
4. Create the SYM file again.
5. Off you go...

Have Phun

Aimless
December 22nd, 2003, 00:56
And before I forget:

Make sure you are in the correct CONTEXT before you do anything else. You can do that by:

1. ADDR (this will give name of all apps. Select your app. If nothing, use the PROC command)
2. ADDR <myapp>
3. Now, BPX "Dialogs::ShowMessage(System::AnsiString)" or BPX MyHack (if you've changed the name in MAP file)
4. Have Phun...

5aLIVE
December 22nd, 2003, 10:01
Thanks guys with you help I got SIce breaking exactly were I wanted.

dETLA - I tried MOSTEK's IDA PlugIn, it works well, saves having to mess about at the command prompt - very convenient . At this point in time I don't fully appreciate the power of the pligin but so far it has served me well.

Aimless - I tried placing the function in quotes but it doesn't like them I tried the @ symbole too.
Changing the name to "MyHack" or similar would do the job nicely, thanks.

I learned from Mostek's manual that breakpoints cannot be set since the function name is mangled and SIce doesn't like these characters '(' ',' or ')'.

If you go to Optionsemangled Names and press 'Setup Short Names' a dBox will open, select the first item 'Inhibit everything except the main name' and press OK.

BPX Dialogs::ShowMessage

I see the stack has a value of 133, now I think I need to use this value to find the calling subroutine? Am I on the right track?

Thanks again.
5Alive

dELTA
December 22nd, 2003, 11:05
What do you mean with "the stack has a value of 133"? Is 133 the value that is on the top of the stack when your Dialogs::ShowMessage breakpoint breaks, or what? The return address of a function is pushed before the parameters (Delphi uses this calling convention too, right, at least I think so, anyone?), and since the Dialogs::ShowMessage function in Delphi only has one parameter, the return address should most likely be located on the second dword stack slot, not the first. But just single-step or "p ret" out of the function and you will be in the calling code anyway, if you can't make any sense of the stack values.

5aLIVE
December 23rd, 2003, 05:54
Yes, I meant ESI has 133 as soon as Dialogs::ShowMessage breaks, my question was based on a hazy recollection on how the stack works. Your reply has helped refresh my memory of their general workings.

The Dialogs::ShowMessage is the "good guy" message, from my reading the "bad guy message" should use Dialogs::ShowMessage to draw a Error MB. I can find no reference to this in the symbols or dead listing.

I've tried setting BPs on every symbol that contains ShowMessage and MessageBox and I can't get the damn thing to break (I'm attached to the context).

I thought if I tried Olly it would maybe give me a clue, the problem is the app loads a splash screen exe before calling the main program.
If I were to attach to the main code I can't do it before the MB is displayed. Olly did show the Application class call the MessageForm class used to display the box/button. I set A BP for Dialogs::TMessageForm - still nothing.

I wonder if using HWND Dialogs::TMessageForm would help? I'll try that next. Can anyone offer some suggestions.

5Alive.

5aLIVE
December 23rd, 2003, 06:00
Sorry, In the abov, I meant the "bad guy" message box should use Dialogs::IvMessageBox, not Dialologs::ShowMesssage, it is still an OK MB, the only differences are that it displays Error in the title and has a graphic in it.

dELTA
December 23rd, 2003, 08:15
In this situation I would probably modify the main exe with a "spinning jump" (a jump directed at itself, hence just "spinning" forever) at OEP. This way you can attach to the new process with your debugger as soon as it's started by that other process, then set any breakpoints and restore it to running state. Then you should be able to break on your messageboxes.

5aLIVE
December 23rd, 2003, 09:22
Hmmm, a spinning jump eh? That sounds like a good idea, I'll give it a go.
It just seems strange that I can break on the "good guy" and not on the "bad guy" when they both occur at soon after the main exe is called, but then what do I know as I'm on a fairly steep learning curve at the moment?

A spinning jump would take the form OEP address: JMP OEP address? Is this corrrect?

Regards 5Alive.

dELTA
December 24th, 2003, 08:22
Yep, that's correct.

5aLIVE
December 24th, 2003, 12:13
Okay, I gave it a go, I used both PEiD and DeDe to find that OEP, this was
found at $002D9D9C, with the first bytes being 55 8B EC 83 (push EBP).
I changed these bytes to E9 9C 9D 2D (JMP $002D9D9C).

I loaded softice and then the app, when the main exe is called by the spash screen SoftICE breaks due to an unhandled exception which reads NTSTATUS = STATUS_ACCESS_VIOLATION
MSR Last ExceptionFromIP = 006D9D9C
MSR LastExceptionToIP = C49B3B3D

As I am fairly new to all this, this error is caused because the the JMP is outside the memory range of the process. So I looked at the OEP info again from PEiD and DeDe. It has an RVA OEP of 006D9D9C, so I changed the last byte from 2D to 6D to give E9 9C 9D 2D (JMP $006D9D9C).

I ran the app again only to get the same type of error. I'm now thoroughly confused, what am I doing wrong?

Thanks,
5Alive

naides
December 24th, 2003, 13:05
Quote:
[Originally Posted by 5aLIVE]Okay, I gave it a go, I used both PEiD and DeDe to find that OEP, this was
found at $002D9D9C, with the first bytes being 55 8B EC 83 (push EBP).
I changed these bytes to E9 9C 9D 2D (JMP $002D9D9C).

I loaded softice and then the app, when the main exe is called by the spash screen SoftICE breaks due to an unhandled exception which reads NTSTATUS = STATUS_ACCESS_VIOLATION
MSR Last ExceptionFromIP = 006D9D9C
MSR LastExceptionToIP = C49B3B3D

As I am fairly new to all this, this error is caused because the the JMP is outside the memory range of the process. So I looked at the OEP info again from PEiD and DeDe. It has an RVA OEP of 006D9D9C, so I changed the last byte from 2D to 6D to give E9 9C 9D 2D (JMP $006D9D9C).

I ran the app again only to get the same type of error. I'm now thoroughly confused, what am I doing wrong?

Thanks,
5Alive



If I may step in:

you are using the long jump (explicit jump) assembly code. Try a short jump $EBFE meaning : JMPS -2, two bytes back, to the begining of the JMPS instruction again, and see if it works.

5aLIVE
December 24th, 2003, 13:19
By all means, I'll try as you suggest. Thanks for your help.
5Alive

dELTA
December 24th, 2003, 18:53
Just like Naides say, use the short jump version instead (it is safe in case of relocation, and just in general less prone to mistakes). Also, if the program is packed, the OEP (Original Entry Point) is not the same as the EP (Entry Point). You must set the jump at the EP in this case, not the OEP (wrong terminology from my side earlier, sorry), and the EP address can always be acquired directly from the PE header of the exe file. Further, if the exe is packed, it might have anti-debugger tricks making life hard for you.

JMI
December 24th, 2003, 21:16
Please excuse any possible mis-cues by dELTA tonight. He has already confessed he's had too much eggnog with his Christmas celebrating.

Regards,

5aLIVE
December 26th, 2003, 09:18
The short/spinning jump worked nicely, I can now single-step to my hearts content.
Having said that, I am still unable to break on a specific message box, though I can break on others in the app. You mention that the if the OEP differs from that of the EP, then then program is packed.

PEiD gives an EP of 002D9D9C and a OEP of 006D9D9C which suggests that it is packed, though in my limited experience I would say that it is not packed (~3.5Mb) as I can readily view the exes resources and view strings in clear text. Any file analyser I have used reports it as a Delphi 4/5 binary.

I can't remember if I set the spinning jump at OEP or EP, I'll need to check on that again. I can't really say with any certainty if the app has anti-debugger tricks, although I would be inclined to think it is trick-free.

Can you suggest anything else I might try to help solve this?

5aLIVE

dELTA
December 26th, 2003, 10:58
I have not used PEiD enough to say why it might do that, but the large exe and correct identfication as a Delphi binary in other programs could theoretically be because it is using a crypter instead of a packer, which might also be so rudimentary as to only crypt the code section and not the data sections (not very likely though, anyone else have any idea why PEiD would report a different EP and OEP in a non-packed executable?). If you disassemble it in e.g. IDA, does the disassembly of the entire code section make sense? (it is often quite easy to recognize crypted code, not to menton that IDA will most likely mark large parts of it as "unknown" if it's crypted) Does it seem to have more than one section containing executable code or unknown "data"?

Anyway, the breakpointing problem might have several reasons. First, it might not be a real messagebox that you're seeing, but a window designed to mimic a messagebox. Second, there is more than one messagebox api that can be used, have you tried to breakpoint them all? Third, a common anti-breakpoint trick is to emulate the first few bytes of such apis inside the own program code, try to put the breakpoint say 10-30 bytes into the api's code in user32.dll instead (only possible in 2000/XP if you're using a ring3 debugger).

Also, if you say that you can see all the strings in plaintext, try to put a memory breakpoont on the string of the "unbreakable" messagebox instead, that should work.

And if all else fails, auto-trace (e.g. in Olly) or single step until the messagebox appears, then you should be able to see exactly where it is located in the code, no matter in which way it is rendered.

5aLIVE
December 26th, 2003, 16:25
Thanks for taking the time to reply again, I hope you don't mind me asking all this stuff.

I've noticed that when I use EP finder in DeDe it shows the Raw EP offset and the PE Header value to be the same(002D919C) and the RVA entry point to be 006D9D9C. Which I see happens to be the image base (00400000) + the RVA entry point. I need to read up on PE headers to understand this properly, do you agree from this that the EP and OEP are in fact the same?
Can I conclude that the binary would not appear to be crypted/packed although it does use symmetric block cipher elsewhere within the program for passwords.

Dissasembling with IDA appears to give a wholly intelligible output, as I haven't come across any parts marked as "unknown". I don't recall seeing more than one section containing code in the data section or unknown "data", though I need to verify this to be certain.

I had wondered about the possibility of it being a fake message box, would a CreateWindow call be used for this purpose or is there another API cal used for this?

I have tried setting BPs for all entries that the command SYM *MessageB* returns to no avail. Are the other Win32 API calls that I may have overlooked?

I'll try setting a BP 10-30 btyes into the use32 dll to see what this brings up (neat little trick). I'm using SI and Olly - can I use either in this case as I'm running XP?

Although I can see the strings in plaintext, the particular MB string has been extracted to a spearate file to allow for multi lingual support. This shouldn't stop me from using the BPM cmd though.

Once again, thanks for all your help and best wishes for the new year.

5Alive.

dELTA
December 26th, 2003, 18:53
Quote:
I need to read up on PE headers to understand this properly, do you agree from this that the EP and OEP are in fact the same?


Yes, that is of course the case (I assume that the differing third-last hex digit in your last post is only a typo, especially since they are equal in your earlier post), I really should have seen that one of them was the VA and the other was the RVA of the same address in your earlier post, have to blame the eggnog again...



Quote:
I had wondered about the possibility of it being a fake message box, would a CreateWindow call be used for this purpose or is there another API cal used for this?


Some of the normal window apis should be used in the end, yes, but this will most likely be deep inside Delphi library code, and might also appear at a much earlier point in time, since all windows in a Delphi application are by default created at program start. I haven't played much with this specific kind of breakpoints lately, does anyone else know this better maybe, with more detailed info?



Quote:
I have tried setting BPs for all entries that the command SYM *MessageB* returns to no avail. Are the other Win32 API calls that I may have overlooked?


That should cover all normal messagebox apis if I'm not mistaken, yes.



Quote:
I'll try setting a BP 10-30 btyes into the use32 dll to see what this brings up (neat little trick). I'm using SI and Olly - can I use either in this case as I'm running XP?


Just to make sure you understood me correctly, this breakpoint should be set 10-30 bytes after the entrypoint of the exported function you want to break on (i.e. not after the entrypoint of the dll itself or something like that), and you must also align it to an instruction (i.e. set the breakpoint on the first byte of some instruction in the code, which in turn can easily be done by viewing the code of the function in the debugger).

5aLIVE
December 28th, 2003, 10:00
After much searching I eventually found the call, its a function called "CreateMessageDialog". I wouldn't have found this without the use of a Delphi ref manual.

I set a BPX on this in SIce and I now know the calling address, looking at the IDA dissassembly reveals that there are lots of calls before it to set up the box, I followed this so far but gave up as it seemed never ending.

I loaded attached to the app with olly and set a BP on the known call address, and sure enough I can see the message box string in EAX when it breaks. I am not familiar with Olly, I thought that by running trace-over (Ctrl-F12) to the call I could back trace the stack to find the test subroutine.

I have a few questions :

1. Is my approach correct? Or is there some way of doing this more easily?
2. I have searched the manual and the web to see how to load a VCL and
SYM files to make my dump more readable, however I cannot seem to
find an answer. How can this be done?

Thanks again for any help.

5aLIVE
December 28th, 2003, 12:40
Aha! I've found the ollydbg.win32asmcommunity.net, it looks like I need to try the MapConv 1.4 plugin to help me on my way. SYM files are not supported from what I read.

Shame I did'y find this earlier
5Alive

dELTA
December 28th, 2003, 19:39
You could also disassemble it in IDA, using the Delphi FLIRT library, and then export all the symbols to Softice with Mostek's great "IDA to Softice" plugin. This is a generic solution that works very well with programs from most compilers, since IDA's FLIRT support is so extensive. Very efficient and very useful.


You can find Mostek's plugin at:

hxxp://mostek.subcultural.com