Reverse Engineering for Beginners

(avery) #1
CHAPTER 21. STRUCTURES CHAPTER 21. STRUCTURES

22 ret 0
23 _main ENDP
24
25 _TEXT SEGMENT
26 _s$ = 8 ; size = 10
27 ?f@@YAXUs@@@Z PROC ; f
28 push ebp
29 mov ebp, esp
30 mov eax, DWORD PTR _s$[ebp+6]
31 push eax
32 movsx ecx, BYTE PTR _s$[ebp+5]
33 push ecx
34 mov edx, DWORD PTR _s$[ebp+1]
35 push edx
36 movsx eax, BYTE PTR _s$[ebp]
37 push eax
38 push OFFSET $SG3842
39 call _printf
40 add esp, 20
41 pop ebp
42 ret 0
43 ?f@@YAXUs@@@Z ENDP ; f


Now the structure takes only 10 bytes and eachcharvalue takes 1 byte. What does it give to us? Size economy. And as
drawback —the CPU accessing these fields slower than it could.

The structure is also copied inmain(). Not field-by-field, but directly 10 bytes, using three pairs ofMOV. Why not 4? The
compiler decided that it’s better to copy 10 bytes using 3MOVpairs than to copy two 32-bit words and two bytes using 4MOV
pairs. By the way, such copy implementation usingMOVinstead of calling thememcpy()function is widely used, because
it’s faster than a call tomemcpy()—for short blocks, of course:43.1.5 on page 486.

As it can be easily guessed, if the structure is used in many source and object files, all these must be compiled with the same
convention about structures packing.

Aside from MSVC/Zpoption which sets how to align each structure field, there is also the#pragma packcompiler option,
which can be defined right in the source code. It is available in both MSVC^7 and GCC^8.

Let’s get back to theSYSTEMTIMEstructure that consists of 16-bit fields. How does our compiler know to pack them on
1-byte alignment boundary?

WinNT.hfile has this:

Listing 21.18: WinNT.h
#include "pshpack1.h"

And this:

Listing 21.19: WinNT.h
#include "pshpack4.h" // 4 byte packing is the default

The file PshPack1.h looks like:

Listing 21.20: PshPack1.h
#if! (defined(lint) || defined(RC_INVOKED))
#if ( _MSC_VER >= 800 && !defined(_M_I86)) || defined(_PUSHPOP_SUPPORTED)
#pragma warning(disable:4103)
#if !(defined( MIDL_PASS )) || defined( __midl )
#pragma pack(push,1)
#else
#pragma pack(1)
#endif
#else
#pragma pack(1)
#endif
#endif /*! (defined(lint) || defined(RC_INVOKED)) */

This tell the compiler how to pack the structures defined after#pragma pack.

(^7) MSDN: Working with Packing Structures
(^8) Structure-Packing Pragmas

Free download pdf