Struct Array problem

BSODMASTER (7)
So can somebody help me with normalizing this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SYS_ERROR MapProfile(SYS_DI_ADAPTER const * a0, SYS_DI_PROFILE * a1, ACTION_TO_TYPE const * a2)
{
	a1->ClearItems();
	const DWORD* v3;
	for(v3 = &a2->m_8; v3; v3+=3)
	{
		SYS_DI_ADAPTER_OBJECT * v4 = a0->FindObject(*v3, 0xFFFFFFu);
		if(v4)
		{
			SYS_DI_PROFILE_ITEM* v7 = new SYS_DI_PROFILE_ITEM(*(v3-1), v4);
			v7->m_12 = a1->m_4;
			a1->m_4 = v7;
		}
		else if(*(BYTE*)(v3-2))
		{
			a1->ClearItems();
			return SYS_ERROR_UNKNOWN;
		}
	}
	return SYS_ERROR_NO;
}


"a2" is a pointer to ACTION_TO_TYPE structure wich is using in this function but I can't understand it's format.

So I think the structure ACTION_TO_TYPE must be somethink like this but I'm not sure:
1
2
3
4
5
6
struct ACTION_TO_TYPE
{
    union { DWORD m_dw; BYTE m_by[4]; } m_0;
	DWORD m_4;
	DWORD m_8;
} ; //size of 12 

or like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
struct ACTION_TO_TYPE_IN_STRUCT 
{
	DWORD m_0;
	union { DWORD m_dw; BYTE m_by[4]; } m_4;
	DWORD m_8;
} ; //size of 12

struct ACTION_TO_TYPE
{
    union { DWORD m_dw; BYTE m_by[4]; } m_0;
	DWORD m_4;
	ACTION_TO_TYPE_IN_STRUCT m_8[]; 
} ; 


Can you help me and give me idea how to interpret this structure? Please help!
Last edited on
BSODMASTER (7)
No replays why? Please help!
toum (169)
There's hardly any information in this code.

1
2
const DWORD* v3;
for(v3 = &a2->m_8; v3; v3+=3)

Tells me that an ACTION_TO_TYPE structure contains an m_8 member which is a DWORD.
If we suppose a2 is an array and that this loop is used to access m_8 in the different elements of the array (that's a lot of ifs), this means that the size of an ACTION_TO_TYPE structure is 3 times the size of a DWORD (padding bytes included).
BSODMASTER (7)
Yes but if it is an array with 12 bytes size, why the pointer is initaliazed firstly with m_8 (NOTE I use m_8 just for looking good actually it must be *((BYTE*)a2+8))? And why then are accessed members above the array (*(BYTE*)(v3-2))? Any more suggestions?
Last edited on
toum (169)
Clearly this code has been written by a sadist without any care for readability or maintainability.
One example: for(v3 = &a2->m_8; v3; v3+=3). If &a2->m_8 is not NULL, this loop may never end.
The only thing that can stop the loop is this condition if(*(BYTE*)(v3-2)) which may read uninitialized memory.

As for *(BYTE*)(v3-2), I guess that the first byte of a valid ACTION_TO_TYPE structure must always be 0.
It's hard to say more.
Last edited on
BSODMASTER (7)
OH I realize a Big Mistake while decompiling this code (yeah the "sadist without any care for readability or maintainability" is me! :O). Actually this need to be the actually code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SYS_ERROR MapProfile(SYS_DI_ADAPTER const * a0, SYS_DI_PROFILE * a1, ACTION_TO_TYPE const * a2)
{
	a1->ClearItems();
	const DWORD* v3;
	for(v3 = (DWORD*)a2 + 2; *v3 /* not v3 */ ; v3+=3)
	{
		SYS_DI_ADAPTER_OBJECT * v4 = a0->FindObject(*v3, 0xFFFFFFu);
		if(v4)
		{
			SYS_DI_PROFILE_ITEM* v7 = new SYS_DI_PROFILE_ITEM(*(v3-1), v4);
			v7->m_12 = a1->m_4;
			a1->m_4 = v7;
		}
		else if(*(BYTE*)(v3-2))
		{
			a1->ClearItems();
			return SYS_ERROR_UNKNOWN;
		}
	}
	return SYS_ERROR_NO;
}


Anyway this actually doesn't make the things clear for me :(. And this code was decompiled so actually I'm wondering for some sort of like behavior of code written not by a sadist (with the rules of C++).

Anyway I found the solution myself :):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SYS_ERROR MapProfile(SYS_DI_ADAPTER const * a0, SYS_DI_PROFILE * a1, ACTION_TO_TYPE const * a2)
{
	a1->ClearItems();
	ACTION_TO_TYPE const * v3;
	for(v3 = a2; v3->m_8; ++v3)
	{
		SYS_DI_ADAPTER_OBJECT * v4 = a0->FindObject(v3->m_8, 0xFFFFFFu);
		if(v4)
		{
			SYS_DI_PROFILE_ITEM* v7 = new SYS_DI_PROFILE_ITEM(v3->m_4, v4);
			v7->m_12 = a1->m_4;
			a1->m_4 = v7;
		}
		else if(v3->m_0.m_by[0])
		{
			a1->ClearItems();
			return SYS_ERROR_UNKNOWN;
		}
	}
	return SYS_ERROR_NO;
}
Last edited on
toum (169)
This looks like the construction of some sort of linked list.

If I had to guess, I'd say a1 is a linked list, a2 an array of elements to add, and a0 some kind of list of authorized values to add to the a1.

Line 7 looks like it checks to see if *v3 is registered in a0, and if that's the case it returns a pointer v4 somehow linked to it.
It then creates a new node using *(v3-1) and v4 and adds it to a1.

Line 14 the fact the only the first byte is checked could be explained by the fact that the first member of a ACTION_TO_TYPE structure is in fact a boolean.
A compiler will generally add padding bytes after a boolean to align the memory address of the next member properly, which could explain why 4 bytes are taken but only 1 is used.

With that hypothesis, I can suggest the following structures:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct ACTION_TO_TYPE
{
    bool booleanValue;
    int value;
    int action;
};

struct SYS_DI_PROFILE_ITEM
{
    int value;
    SYS_DI_ADAPTER_OBJECT * actionPtr;
    SYS_DI_PROFILE_ITEM * nextNode;
    
    // constructor
    SYS_DI_PROFILE_ITEM(val,actPtr) : value(val), actionPtr(actPtr), nextNode(NULL) {;}
};

struct SYS_DI_PROFILE
{
    SYS_DI_PROFILE_ITEM * listHead;
    /* ... */
};


And your code could be rewritten like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SYS_ERROR MapProfile(SYS_DI_ADAPTER const * a0, SYS_DI_PROFILE * a1, ACTION_TO_TYPE const * a2)
{
	a1->ClearItems();
	for(int n = 0; a2[n].action != 0; n++)
	{
		SYS_DI_ADAPTER_OBJECT * actionPtr = a0->FindObject(a2[n].action, 0xFFFFFFu);
		if(actionPtr != NULL)
		{
			SYS_DI_PROFILE_ITEM* newNode = new SYS_DI_PROFILE_ITEM(a2[n].value, actionPtr);
			newNode->nextNode = a1->listHead;
			a1->listHead = newNode;
		}
		else if( a2[n].booleanValue == true )
		{
			a1->ClearItems();
			return SYS_ERROR_UNKNOWN;
		}
	}
	return SYS_ERROR_NO;
}

Registered users can post here. Sign in or register to post.