Patching a Null Pointer Access Violation

An application was crashing about 5x a time a day so crash dumps were enabled via registry https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx

Looking at the dmp files the program always crashed at same point in the program.

This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(51c.1160): Access violation – code c0000005 (first/second chance not available)
ntdll!NtWaitForMultipleObjects+0xa:
00007ff9`b879ed4a c3              ret
0:007> .ecxr
rax=0000000000000000 rbx=000000412a47e678 rcx=0000000000000010
rdx=000000412605e6c0 rsi=000000412a47d798 rdi=0000004123d9a040
rip=00007ff994a0a260 rsp=000000412605ea70 rbp=000000412a46e350
r8=00000041238b3820  r9=00000041280b7b10 r10=000000412380f430
r11=000000412605e230 r12=0000000000000004 r13=00007ff994a370f0
r14=00007ff9b21b1c80 r15=0000000000000000
iopl=0         nv up ei ng nz na pe cy
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010283
Updater!GetSettingsCollection+0x760:
00007ff9`94a0a260 443920         
cmp     dword ptr [rax],r12d ds:00000000`00000000=????????

While I waited for patch from vendor, I wanted to experiment patching the crash on my own. For patching I’ve used IDA Pro.

To easily find the code in IDA pro I first dumped the crash location in bytes:

0:007> db Updater!GetSettingsCollection+0x760
00007ff9`94a0a260  44 39 20 74 0c 83 38 06-75 0c 83 f9 40 74 07 eb  D9 t..8.u…@t..
00007ff9`94a0a270  aa 41 3b cc eb f7 48 8b-5c 24 40 48 8b 03 4c 8b  .A;…H.\$@H..L.
00007ff9`94a0a280  70 40 49 8b ce ff 15 9d-63 02 00 48 8d 54 24 58  p@I…..c..H.T$X
00007ff9`94a0a290  48 8b cb 41 ff d6 89 44-24 30 85 c0 0f 89 85 00  H..A…D$0……
00007ff9`94a0a2a0  00 00 e8 6d e6 00 00 83-38 02 0f 86 6b ff ff ff  …m….8…k…
00007ff9`94a0a2b0  c7 44 24 50 4c 0a 00 00-4c 89 ac 24 00 01 00 00  .D$PL…L..$….
00007ff9`94a0a2c0  48 c7 84 24 08 01 00 00-44 00 00 00 48 8d 4c 24  H..$….D…H.L$
00007ff9`94a0a2d0  50 48 89 8c 24 10 01 00-00 48 c7 84 24 18 01 00  PH..$….H..$…

I then loaded the faulting module, updater.dll, into IDA and searched for the first 8 bytes by clicking Search –> Find Sequence of Bytes. I also enabled Find all occurrences just in case this byte sequence re-occurred

image

With only one result, we found what we are looking for:

image

To find a place to insert my patch code, I went to end of the .text segment where we found alignment bytes

align 100h

To insert patch code we selected the align statement and changed it to code (‘C’ keyboard shortcut, or Edit –> Code )

So now we had something like this

db 0
db 0
db 0
etc

The patching code I wanted to insert would check if rax = 0 , if so jump to the location where [rax] was no longer used.

Something like

cmp rax,0
jz <Skip use of [rax]>
jmp <return to code using [rax]>

IDA’s Hex-Rays doesn’t support assembling x64 code, so I couldn’t use “assemble” to generate the byte code for the cmp instruction.

If I don’t know the byte code, I just did a quick search for similar instruction, and used the bytes from it – by searching for cmp rax, I found the bytes I needed

For the jump instructions I found jz near ptr loc_address works fine. However IDA will only assemble this if there is already a jump to that location, otherwise it will fail “Invalid Operand”

To manually calculate the jump, we take the subtract source & destination addresses:

18002FF31 (Source Address) – 18000A265 (Destination Address) = 25CCC + 5 (length of our jmp instruction) = 25CD1. Because we are jumping “backwards” make negative = FF FD A3 2F

I just used the Windows calculator in “hex mode” To get the negative hex number calculated 0 minus 25CD1.

Convert to Little Endian (Reverse Bytes) = 2F A3 FD FF

 

E9 is the op code for the relative jmp we need, so based on this calculation our jmp instruction is

E9 2F A3 FD FF

We insert these using IDA’s Edit –> Patch Program –> Change Bytes

Original Code

.text:000000018000A251 loc_18000A251:      
.text:000000018000A251                 mov     rax, [rsp+388h+var_2F8]
.text:000000018000A259                 mov     rax, [rax+108h]
.text:000000018000A260                 cmp     [rax], r12d <—Crash
.text:000000018000A263                 jz      short loc_18000A271
.text:000000018000A265                 cmp     dword ptr [rax], 6
.text:000000018000A268                 jnz     short loc_18000A276
.text:000000018000A26A                 cmp     ecx, 40h
.text:000000018000A26D
.text:000000018000A26D loc_18000A26D:  
.text:000000018000A26D                 jz      short loc_18000A276
.text:000000018000A26F                 jmp     short loc_18000A21B

Jump to Patched Code

000000018000A251 loc_18000A251:     
.text:000000018000A251                 mov     rax, [rsp+388h+var_2F8]
.text:000000018000A259                 mov     rax, [rax+108h]
.text:000000018000A260                 jmp     patched_code
.text:000000018000A265                 nop     ; because we couldn’t fit some
.text:000000018000A266                 nop     ; instruction here
.text:000000018000A267                 nop
.text:000000018000A268
.text:000000018000A268 loc_18000A268: ;
.text:000000018000A268                 jnz     short loc_18000A276
.text:000000018000A26A
.text:000000018000A26A loc_18000A26A:
.text:000000018000A26A                 cmp     ecx, 40h
.text:000000018000A26D
.text:000000018000A26D loc_18000A26D: 
.text:000000018000A26D                 jz      short loc_18000A276
.text:000000018000A26F                 jmp     short loc_18000A21B
.text:000000018000A271

.text:000000018000A271 loc_18000A271:         
.text:000000018000A271                 cmp     ecx, r12d
.text:000000018000A274                 jmp     short loc_18000A26D

The Patch:

.text:000000018002FF1F patched_code:                           ; CODE XREF: sub_180009B00+760j
.text:000000018002FF1F                 cmp     rax, 0
.text:000000018002FF23                 jz      loc_18000A21B ; If RAX=0 skip [RAX] code
.text:000000018002FF29                 cmp     [rax], r12d ; RAX!=0 continue on
.text:000000018002FF2C                 jz      loc_18000A271
.text:000000018002FF32                 cmp     dword ptr [rax], 6
.text:000000018002FF35                 jmp     loc_18000A268 ; continues normal execution of program

Once we were ready to test the changes we applied them by selecting Edit –> Patch Program –> Apply Patches to Input File

I always ensure I have a backup of original file, as it is quite easy to break something.

imagew

This patch did happen to resolve this crash. However doing this type of patch will frequently lead to other types of crash or bugs, and so can be a very time consuming process.

However it is important to remember, lost source code or bad vendor support, does not mean bugs can’t be fixed…

About chentiangemalc

specializes in end-user computing technologies. disclaimer 1) use at your own risk. test any solution in your environment. if you do not understand the impact/consequences of what you're doing please stop, and ask advice from somebody who does. 2) views are my own at the time of posting and do not necessarily represent my current view or the view of my employer and family members/relatives. 3) over the years Microsoft/Citrix/VMWare have given me a few free shirts, pens, paper notebooks/etc. despite these gifts i will try to remain unbiased.
This entry was posted in IDA, Patching, WinDbg and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s