Contents

Practical Reverse Engineering Exercise Solutions: Page 79 / Exercise 9

Contents

Exercise 9 on page 79 of the book Practical Reverse Engineering specifies the following ARM disassembly of a function called mystery9:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
01:             mystery9
02: 2D E9 30 48   PUSH.W   {R4,R5,R11,LR}
03: 0D F2 08 0B   ADDW     R11, SP, #8
04: 09 4D         LDR      R5, =byteArray
05: 06 E0         B        loc_100E312

06:      loc_100E304
07: 0B 78         LDRB     R3, [R1]
08: 5A 5D         LDRB     R2, [R3,R5]
09: 63 5D         LDRB     R3, [R4,R5]
10: 93 42         CMP      R3, R2
11: 04 D1         BNE      loc_100E318
12: 01 30         ADDS     R0, #1
13: 01 31         ADDS     R1, #1

14:      loc_100E312
15: 04 78         LDRB     R4, [R0]
16: 00 2C         CMP      R4, #0
17: F5 D1         BNE      loc_100E304

18:      loc_100E318
19: 0B 78         LDRB     R3, [R1]
20: 5A 5D         LDRB     R2, [R3,R5]
21: 03 78         LDRB     R3, [R0]
22: 5B 5D         LDRB     R3, [R3,R5]
23: 98 1A         SUBS     R0, R3, R2
24: BD E8 30 88   POP.W    {R4,R5,R11,PC}
25:             ; End of function mystery9

First of all, mystery9 has a striking similarity to the previously decompiled function mystery8. Its disassembly uses Thumb mode, as we can see for instance from the 16 bit instruction width.

In contrast to mystery9, it takes only two arguments of type char* (strings) and no additional limiting variable. The return value is a signed 32 bit integer, as we can see from line 23. The provisional function prototype is as follows:

1
sint32 mystery9 (char* arg1, char* arg2);

Merely by looking at the disassemblies, we see that mystery9’s functionality can be considered a subset of mystery8’s functionality. With the decompilation, the similarity becomes even more evident:

1
2
3
4
5
6
7
8
9
sint32 mystery9 (char* arg1, char* arg2) {
 while (*arg1 != 0) {
  if (byteArray[*arg1] != byteArray[*arg2]) {
   arg1++;
   arg2++;
  }
 }
 return byteArray[*arg1] - byteArray[*arg2];
}

The variable byteArray has the same properties as in the function mystery8, i.e. it is an array holding the entire byte value range at the corresponding index : {0, 1, …, 0xFE, 0xFF}. Likewise, the usage of byteArray can be omitted, since the index and array value are identical:

1
2
3
4
5
6
7
8
9
sint32 mystery9 (char* arg1, char* arg2) {
 while (*arg1 != 0) {
  if (*arg1 != *arg2) {
   arg1++;
   arg2++;
  }
 }
 return *arg1 - *arg2;
}

As already mentioned, it essentially performs the same computations as mystery8, however, it does not take a limiting parameter. As a result, it continues in the main loop until the end of both strings or a differing character is found. The return value is the numerical difference between the first differing characters in the strings and thus, when no difference can be found, the value 0.

Therefore, the possible return values are:

  • 0: Both strings are equal
  • >0: The numerical value of the first differing character is greater in arg1 than in arg2
  • <0: The numerical value of the first differing character is smaller in arg1 than in arg2

Lastly, we provide a more descriptive version of mystery9:

1
2
3
4
5
6
7
8
9
sint32 strcmp(char* str1, char* str2) {
 while (*str1 != 0) {
  if (*str1 != *str2) {
   str1++;
   str2++;
  }
 }
 return *str1 - *str2;
}