Using Pintool can speed up the work that I would do with debuggers otherwise. When analyzing with Pintool I don't see all the non-relevant instructions that a debugger would show up but rather see more, and more relevant information. Therefore I can focus better on what's important.
I picked up an uncompressed flash file - with FWS signature in its header - and loaded it in the standalone Flash Player 22.214.171.124 (flashplayer_12_sa.exe).
When executing, the flash file is read by a loop of
0x10000as the number of bytes (64Kb) to read in each iteration. Once
ReadFile()receives the bytes read from the file, the bytes are copied to the permanent buffer.
_fastcopy_Iis used to copy bytes to the permanent buffer that has RVA of
0x70c396. Note, it's reasonable to assume there might be other copy functions embedded in Flash Player for different architectures.
Many bytes in the permanent buffer are just propagated to other buffers. Otherwise, a validation is directly performed by dereferencing certain regions of the permanent buffer. I was looking at the latter as I'd inspect the data flow on a deeper level at a later date. One such validation on the permanent buffer is the following inline
strlen()core, that has RVA of
0040a922 8a08 mov cl,byte ptr [eax]
0040a924 40 inc eax
0040a925 84c9 test cl,cl
0040a927 75f9 jne FlashPlayer!WinMainSandboxed+0x176a8 (0040a922)
Instructions dereference the permanent buffer from 42 ditinct locations in Flash Player. I had a look at the addresses with their surrounding code and found the inline
strlen()core above to be the most interesting. Note, the above inline
strlen()core can be found at multiple locations in Flash Player.
There are couple of reasons I found the above code interesting. When looking at the surrounding code I didn't see sanity check of the string size. The position in the buffer can be projected back to the position in the flash file by Pintool. At this point, I suspected I had good control over the string size as I can make it to be a long string and even I can remove the ending zero in the flash file without causing Flash Player to bail out early.
Below is the screenshot of the flash file.
strlen()is triggered on "movieLoader" string ending with zero. It's highlighted.
I was considering to alter the flash file in a way to overwrite the ending zero of the string, and all subsequent zeros in the following tags (DefineButton2, PlaceObject2, etc). It would mean the string would run until the end of the file hoping
strlen()to read out of the bounds. Actually, when experimenting, I took the plunge to remove the last few tags and appended few "A" characters to the string until end-of-file, without ending zero. Also, adjusted the file size in the header as it was obligatory. Here is a photo of the string.
I run Flash Player and saw in the log produced by Pintool that the inline
strlen()is triggered meaning it processes the altered string. This is good because the code is still reachable when reading the corrupted string. However an unexpected zero byte beyond the string causing the loop to break without Flash Player entering in an inconsistent state or reading out of bounds.
I wanted to know how the zero byte is set at the end of the string so I changed Pintool to log all write accesses on the permanent buffer. When I run Flash Player again, I didn't see in the log that zero byte is set at the end of the string. As being paranoid today, I immediately thought that might be an uninitialized value that is zero by chance but this was a guess so thought better check how the memory is allocated for the permanent buffer. I added the required code to Pintool to see how the memory is allocated and I saw it is allocated by
VirtualAlloc. This explains the zero byte as memory allocated with this function is automatically initialized with zero.
I was thinking if I can construct the flash file to place the string at the end of memory page without leaving space for padding zero bytes. I was able to control the amount of memory to allocate by changing the file size field in the flash file (at offset
4). What I observed is that the size of allocated memory is always bigger than the file size in the header and so there are always padding bytes. In my experiment I saw the pattern that the amount of memory to be allocated is calculated by incrementing the file size by one and rounding up to the nearest multiple of
It seems defense against this string attack is consciously added by Adobe preventing to read out of bounds.