tum-i4 / self-checksumming

10 stars 6 forks source link

GuardMe call ignores the fact that expected hash is loaded in the binary #47

Closed mr-ma closed 6 years ago

mr-ma commented 6 years ago

Reported by @dennisfischer

Given following the LLVM IR:

129   %a7 = alloca i32
130   %b8 = alloca i16
131   %c9 = alloca i32
132   store i32 628175011, i32* %a7
133   store i16 23905, i16* %b8
134   store i32 1656478042, i32* %c9
135   %4 = load i32, i32* %a7
136   %5 = load i16, i16* %b8
137   %6 = load i32, i32* %c9
138   call void @guardMe(i32 %4, i16 %5, i32 %6), !guard !4

We get the following binary representation (of course after post patching guards):

|           0x00400de0      c745d8700d40.  mov dword [local_28h], sym.f20                                                                                                                 
|           0x00400de7      66c745e84400   mov word [local_18h], 0x44  ; 'D'                                                                                                              
|           0x00400ded      c745c4370000.  mov dword [local_3ch], 0x37 ; '7'                                                                                                              
|           0x00400df4      8b7dd8         mov edi, dword [local_28h]                                                                                                                     
|           0x00400df7      0fb775e8       movzx esi, word [local_18h]                                                                                                                    
|           0x00400dfb      ba5ad9bb62     mov edx, 0x62bbd95a                                                                                                                            
|           0x00400e00      e8db000000     call sym.guardMe            ;[1]    

Despite the fact that the expected hash is loaded:

mov dword [local_3ch], 0x37 ; '7'

The corresponding argument in the binary representation for guardMe is read from a constant value, which must be read (I EXPECT) from the loaded value.

|           0x00400dfb      ba5ad9bb62     mov edx, 0x62bbd95a       

This problem duplicates expected hash tokens, and since the post patcher expects one patch per token, some placeholders remain unpatched. Therefore, false tamper detection is taking place in the protected binaries.

A harmless hack is to extend the post patcher to patch all the occurrence of tokens in the binary.

This should not affect #1.

mr-ma commented 6 years ago

The problem is solved, i.e., we don't get false alarms.

|           0x00400de0      c745d8700d40.  mov dword [local_28h], sym.f20                                                                                                                 
|           0x00400de7      66c745e84400   mov word [local_18h], 0x44  ; 'D'                                                                                                              
|           0x00400ded      c745c4370000.  mov dword [local_3ch], **0x37** ; '7'                                                                                                              
|           0x00400df4      8b7dd8         mov edi, dword [local_28h]                                                                                                                     
|           0x00400df7      0fb775e8       movzx esi, word [local_18h]                                                                                                                    
|           0x00400dfb      ba37000000     mov edx, **0x37**               ; '7' ; 55                                                                                                         
|           0x00400e00      e8db000000     call sym.guardMe            ;[1]             

As illustrated in the sample snippet, the placeholder corresponding to 0x37 is patched twice, once in the load and another time when the argument is being prepared for the guardMe call. This is particularly bad when we apply OH, as constants are not properly (if not at all) protected by OH.

Why the compiled binary doesn't respect the LLVM IR remains a mystery to me! @anahitH Any ideas?