Solved

C++ struct to Delphi

Posted on 2004-04-20
11
1,863 Views
Last Modified: 2012-08-13
This question is a bit extended..
I am trying to use an exported function of another DLL that looks like this:
void __fastcall PrintMessage(ptMsg * Message)

I need to convert this structure to a Delphi structure. I can convert some of it but i get stuck in the boolean and the string parts:

struct ptMsg
{
 BYTE Unk0;
 BYTE id;
 BYTE Unk1;
 BYTE type;
 bool overhead;
 byte Unk2[3];
 WORD Unk3;
 char PlayerName[0x10];
 char Message[542]
};

I need the new structure in delphi to have the same number of bytes since it will be passed into the function

(I can probably figure the part below myself but any help is appreciated and will be awarded pts)

The beginning of the function looks like this in ASM (used madshi's madAsm)
6fb1e120 sub_6fb1e120:                    ; function entry point
6fb1e120   sub     esp, $dd8
6fb1e126   push    ebx
6fb1e127   push    ebp
6fb1e128   mov     ebp, ecx
6fb1e12a   push    esi
6fb1e12b   push    edi
6fb1e12c   mov     al, [ebp+3]
6fb1e12f   test    al, al
6fb1e131   jnz     loc_6fb1e143
6fb1e131
6fb1e133   mov     ecx, [ebp+4]
6fb1e136   call    -$6d61b ($6fab0b20)
6fb1e136
6fb1e13b   test    eax, eax
6fb1e13d   jz      loc_6fb1e656
6fb1e13d

Since it uses fastcall, I think I will have to change the function a bit from
procedure PrintMessage(mMessage: ptMsg)
so that it sends the parameters correctly.
0
Comment
Question by:GiulianoB
  • 4
  • 3
  • 2
  • +2
11 Comments
 

Author Comment

by:GiulianoB
Comment Utility
For the second part, I am thinking of making a wrapper DLL that will export the functions in STDCALL format. Would that work ?
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility

The struct part I can help you with (to a point)...

type
  // You need to figure out the byte alignment the dll was compiled with...
  // eg, this may need to be: ptMsg = record
  lpPtMsg       = ^ptMsg;
  ptMsg          =  packed record
     Unk0:       Byte;
     id:         Byte;
     Unk1:       Byte;
     _type:      Byte;
     overhead:   BOOL; // Defined in Windows.pas (4 byte long bool)
     Unk2:       Array [0..2] of Byte;
     Unk3:       Word;
     PlayerName: Array [0..15] of Char;
     Message:    Array [0..541] of Char;
  end;

Problem is, its impossible to tell the byte alignment of the structure (no C\C++ source context to go from). Where it would end up getting messed up is after the Unk2 field, which is 3 bytes long (if not packed). Unless you know for sure, this will be a trial and error situation.

Regarding the fastcall declaration...
This is kind of a combination of register PLUS stdcall calling convention:

(I quote)
The first two parameters are passed in ECX and EDX, with the remainder passed on the stack as in __stdcall. Again, the callee cleans the stack. Function names are decorated by a leading @-sign and a trailing @-sign followed by the number of bytes of parameters taken by the function (including the register parameters).

Anyways, there is no calling convention in Delphi that "quite" fits this. I offer this suggestion (I take no credit for it, as Madshi has mentioned this in another question somewhat similar to this; I only agree with his suggestion as well).

Pad the function with 2 integer params before the Message param, thus making the
Message param come in as ECX (Delphi passes in EAX, EBX, ECX...) . Leave the function calling convention alone (it will be register by default). As the register function cleans up after the call, you **should** be ok.

Example:
procedure PrintMessage(Fill1, Fill2: Integer; Message: lpPtMsg); external 'dllname';

--------

Regarding  your other suggestion. A wrapper would work as well, as long as the wrapper language understood the __fastcall calling convention. (meaning, it needs to be done in C/C++). This would be the safest way IMHO...

Hope this helps,
Russell

0
 
LVL 3

Expert Comment

by:MikProg
Comment Utility
Windows.pas in Delphi source contains {ALIGN ON} compiler directive.
Delphi help says:
In the {$A8} or {$A+} state, fields in record types that are declared without the packed modifier and fields in class structures are aligned on quad word boundaries.
If you owner C++ & Delphi code then making same alignment in both sources same used in windows dll's is good idea
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
Sounds to me like Russell earned the points this time...   :-)
0
 
LVL 11

Expert Comment

by:robert_marquardt
Comment Utility
I would bet on packed record. Unk3 being the first and only candidate for alignment seems to indicate that packing was considered when the record was designed.
0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 20

Expert Comment

by:Madshi
Comment Utility
I'm just wondering. The alignment would be perfect if the "bool" would only be 1 byte long. Is that possible? Does a one byte bool exist in C++ or is it always 4 bytes?
0
 

Author Comment

by:GiulianoB
Comment Utility
I'm not home at the moment but i will try when I get home. Thanks
0
 

Author Comment

by:GiulianoB
Comment Utility
I have this also btw:
it's the same structure but diff variable names.. this has the sizes
struct ChatMsg {
   BYTE Identifier;        // 0x00
   BYTE MessageType;       // 0x01
   BYTE Unk1;              // 0x02
   BYTE Style;             // 0x03
   DWORD UnitId;           // 0x04
   BYTE Color;             // 0x08
   BYTE Unk2;              // 0x09
   char Name[0x10];        // 0x0A
   char Message[0x100];    // 0x1A
};

also will the method to add 2 fill integers work on any fastcall or does it have to have a certain amt of parameters ?
0
 
LVL 26

Accepted Solution

by:
Russell Libby earned 175 total points
Comment Utility

I would bet on packed record as well, as it is typically the norm (especially nowadays). But then again, looking at a library that exports functions as __fastcall doesn't leave me with a lot of confidence in that bet ;-)

Regading the bool issue: Yes, it could be 1 byte. The bool data type is not part of the standard ANSI C, and it was usually the case to typedef it as an int. It IS part of the C++ standard, but not all compilers are standard in the implementation of such things. So, this is just another case where context means everything. I will offer this though...

Looking at the declaration again, it would appear that this is not the bool data type from the windows header, as the windows header type define is "BOOL"
(and C/C++ is case sensitive). So, there is a very good chance that the compiler's native data type was used.

Anyways, it would have been nice to see a "bool" field (with size comments) in the second struct listing.

Also, I made a mistake with my statement on Delphi's passing. Delphi passes up to 3 values in the registers, but the registers are:

EAX, EDX, ECX // not EAX, EBX, ECX

My apologies on that (It was late, and I was tired...). You still need to pad the function 2 places, as suggested. For _fastcall declarations with 2 params, the declaration would be

function foo(Filler: Integer; Param2: datatype; Param1: datatype);

Please note the reverse order of param1 and param2 in order to get them into their correct registers. In regards to calling _fastcall functions with more than 2 parameters.... well, let's just say that I personally would not want to touch it.

----------

Russell


0
 

Author Comment

by:GiulianoB
Comment Utility
I haven't tested it all but I understand a lot better and that's what I wanted to accomplish. Thanks!
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Let us know if you run into any issues, and I (and hopefully others) will try to assist.

Russell

0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
This video discusses moving either the default database or any database to a new volume.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

6 Experts available now in Live!

Get 1:1 Help Now