Author: ski
Especially for xss.pro
In-line patching is not the easiest way to change the behavior of a program since it requires a good knowledge of the packer's operating mechanisms, but once the concepts that govern its operation have been assimilated, it can be easily extended to packers of different types.
From the point of view of efficiency it is certainly a winning technique compared to unpacking since the final patch is generally much smaller than those of the uncompressed executable, as it takes longer than unpacking.
the Chord Pickout program (version 1.5) was used
Using a file scanner, the executable is analyzed to find out if it has been compressed or not.
This is confirmed by the classic structure of the entry point of the program presented by ASProtect:
As a general approach to perform in-line patching, you must first identify the OEP (or an area near it) of the application, using the usual technique of exceptions this is easily found in:
We restart the program and position ourselves in the OllyDbg dump window, press CTRL+G and write the address of the OEP 0x00499914, in this way we try to identify from which area of ASProtect memory the code that starts from the OEP is written.
The addresses all contain null bytes since the program code still needs to be unpacked from the packer stub, so we put a breakpoint on memory write in the OEP byte:
Check all the exceptions in the OllyDbg options window (ALT+O) and press Shift+F9 to start the program, OllyDbg crashes in this part of the code:
pressing F8 once executes the write loop, you have in the dump window:
To see the disassembled:
Getting:
The code is obviously not clear since OllyDbg could not have parsed it when loading the program since the code had not yet been unpacked from the packer stub so we go to the OllyDbg queue window, press CTRL+G and write the address to be parsed, then 0x00499914 and press Enter, at this point force the parsing by pressing CTRL+A:
Bingo, the code has been unzipped and matches what we found earlier by skipping the exceptions.
At this point we know that the writing of the OEP code takes place from a memory area that starts from (ALT+M to view the memory map of the running process):
This area does not belong to the sections already existing on disk since it is not contemplated in the PE-Header and is precisely an area dynamically allocated by the packer that first requests memory from the system and then fills it with the code that will then execute and that in the case analyzed takes care of decompressing the program code. Since this is an area of memory allocated at run-time, it will not be found when the program is loaded, but it will be necessary to identify when it is actually allocated in order to trace it with the in-line code. To do this we have to perform a minimum of packer reversing by identifying the sequence of dynamically allocated areas and tracking their execution with our in-line code. The first thing to do then is to find an entry point from the ASProtect stub that allows us to keep memory of the first memory allocation made by the packer, in this regard we restart everything with CTRL+F2. Let's remove all the checkmarks on OllyDbg's handling of exceptions (ALT+O to quickly access the Debugging options window) except for the first exception:
We press CTRL+G and write VirtualAlloc which is the API used to request run-time memory from the system, an API that is used by ASProtect to allocate the memory areas that will be filled with the packer code itself. Then let's put a breakpoint as illustrated below:
We press Shift+F9 and OllyDbg gets stuck in our API, we press ALT+F9 to return to the code from which the API call was made and we also take note of the address contained in the EAX:
OBSERVATION: The value 0x00B30000 assumed by EAX in general may differ from machine to machine since
turns out to be the address of a memory area allocated at run time.
The memory map of the process under consideration (ALT+M) is as follows:
As you can see, the area we saw before interested in the decompression of the code at the OEP is not yet present, this means that the area in question belongs to a layer that will be decompressed at run-time at a later time. At this point, however, we have to see if the code that calls the VirtualAlloc is already available at the time of the first loading of the program, that is, when we are in the entry point of the packer.
To do this, press CTRL+F2 to return to the entry point and then let's see what we find at the address 0x004EB4E1:
The code is different from the one seen previously, this means that ASProtect performs preliminary code decryption operations before calling the VirtualAlloc, so we have to identify where this code is written, to do this we can restart the program and put a memory breakpoint in writing at the address 0x004EB4E1 in order to identify the point where the code is actually written.
In particular, we have:
press Shift+F9 and OllyDbg locks at address 0x004EB13F, the next call, if executed by pressing F8, decrypts all the code.
Let's restart OllyDbg with CTRL+F2 and from the entry point let's see what we have at address 0x004EB142, yup, now the code is exactly what it should be so we have identified a potential entry point to be able to track the execution of the code. If you execute the code step-by-step using F7 you can easily realize that we are inside the decompression loop, I report all the code with some NOPs inserted that de-obfuscate the code itself making it clearer what the packer does, in short the various calls inside the loop are used as if they were jumps.
The only exit point of the code is at address 0x004EB1AA, so let's put a breakpoint at this point and press Shift+F9, when OllyDbg crashes we notice that the code at the destination of the JMP has changed, a sign that the decompression loop has done its job, thanks to ASProtect.
Now let's restart OllyDbg with the usual CTRL+F2 and let's go immediately to see the code at the address 0x004EB1AA:
we have the plaintext code of the jump that is made at the end of the decryption loop, very good, this can be a nice point of attack to be able to insert the first redirect to the in-line patching code, so let's take note of it:
FINE LOOP#1: 0x004EB1AA
ORIGINAL INSTRUCTION: JMP 0x004EB1CA
Once we reach the JMP, i.e. after we have completely looped, we must also check if the code at the address of the first VirtualAlloc has actually been decrypted. In this regard, we then press CTRL+G and write 0x004EB4E1, the code unfortunately has not yet been decrypted, so we proceed with the analysis of the code using the single step with F7, after a few instructions we encounter again a decryption loop with obfuscated code.
The exit from this loop is at address 0x004EB267, so we put a software breakpoint (F2) and press Shift+F9 to execute the whole loop.
As usual, we take note of the address at which the loop ends and the original instruction:
FINE LOOP#2: 0x004EB267
ORIGINAL INSTRUCTION: JMP 0x004EB290
Also in this case the new code is decrypted, as we did previously we go to see if the code at VirtualAlloc has been decrypted, also in this case it has not yet been written, so let's proceed with the single step, now we are close to the conclusion of this first phase. An additional loop is easily identified:
insert a memory breakpoint at the exit point and press Shift+F9 to loop the entire loop.
We always take note of the address and instruction at the end of the loop:
FINE LOOP#3: 0x004EB32D
ORIGINAL INSTRUCTION: JMP 0x004EB373
Let's check again if the code that takes care of calling the VirtualAlloc has been decrypted by pressing CTRL+G and entering the 0x004EB4E1 address, we are not there yet, so we must continue to trace. Let's restart OllyDbg and put the breakpoint at the end of the first loop 0x004EB1AA and press Shift+F9, then put the breakpoint at the end of the second loop in 0x004EB267 and press Shift+F9 and finally the breakpoint on the third loop in 0x004EB32D and press Shift+F9. Now we have passed all three of the first three loops, we continue to track with F7. As expected, there is a further decryption loop, this time slightly different from the previous ones and to some extent easier to analyze.
You put a breakpoint at the end of the loop and run it with Shift+F9.
FINE LOOP#4: 0x004EB410
ORIGINAL INSTRUCTION: CALL 0x004EB427
Check if the code that calls the VirtualAlloc is finally decrypted:
YEPP finally we have arrived, now the code that takes care of calling the VirtualAlloc has been decrypted.
To recap what has been done so far, the packer performs the following operations:
1. We are at the entry point in
2. The first decryption loop is performed until the output in 0x004EB1AA
3. The second decryption loop is performed until the output is 0x004EB267
4. The third decryption loop is performed until the output in 0x004EB32D
5. The fourth decryption loop is performed until the output in 0x004EB410
6. You will arrive at the address of the VirtualAlloc call in 0x004EB4E1
As a breakpoint (to be activated sequentially starting from the Entry Point and after each loop has been executed) we have:
Continuing to trace we arrive at the instructions that call the VirtualAlloc, in particular we have two calls, a loop that writes the code in the area we are interested in dynamically allocated by the second call to the VirtualAlloc and finally a jump within the new area.
The push 0BA1000 followed by the RETN jumps to the allocated area and in particular to the offset related to the PUSH 8000 instruction it is possible to retrieve in EDI the base address of the region to which it jumps once the RETN has been executed at the end of the routine. we can then use the space associated with the PUSH 8000 to redirect execution to our in-line code.
ADDRESS: 0x004EB5E8
ORIGINAL STATEMENT: PUSH 8000 -> 0x68 0x00 0x80 0x00 0x00
The execution jumps to the regions allocated by ASProtect at the 0x0031000 offset. The offset is important since the regions do not have absolute addresses in memory. We are now in the memory area that will perform the decompression of the code to the OEP.
If we look at the code at address 0x00B72663 (offset 0x002663 from the base address) we notice that the code is different from the one seen at the beginning of our analysis, this is because we have to go through additional decompression layers before the ASProtect code that takes care of writing the OEP is in plain text and is executed.
Let's resume the analysis from the 0x00BA1007 address, if we proceed step by step in the code we arrive at a further call of the VirtualAlloc in 0x00BA10C4 continuing step by step we have a write loop.
which brings us to a new leap to 0x003130D offset. Also in this case it is advisable to identify a point where we will jump to our in-line code and this can be done again by identifying the PUSH 8000 instruction so we will have:
OFFSET: 0x00310F3
ORIGINAL STATEMENT: PUSH 8000 -> 0x68 0x00 0x80 0x00 0x00
We continue the analysis of the code by tracing with F8 and checking in the OllyDbg dump window if the code at the 0x00B72663 address is decrypted, so far the code has not yet been written, so we continue with the analysis. We reach the RETN statement and press F8, at the offset 0x0031343 we have a new call to the VirtualAlloc.
Continue with F8 to the offset 0x00313C7 here is the loop that writes the part of the code that takes care of decompressing the code to the OEP. Let's mark the offset of the PUSH 8000 instruction that will be used for the next redirection:
OFFSET: 0x00313D7
ORIGINAL STATEMENT: PUSH 8000 -> 0x68 0x00 0x80 0x00 0x00
In fact, if we press F8 once and observe in the dump window set to the display of the dissasas, we have the code in plain text:
Continuing the analysis we arrive at a rather interesting block of code since it seems to have to do with the IAT, in fact two loops are identified, one external and one internal:
the decoded APIs are written starting from the offset, 0x002C104, the loop ends at the offset 0x00315AB.
If you run the whole loop you get to the breakpoint on the MapViewOfFile, you press ALT+F9, you get to a part of the code where you have three PUSHs 0 this one doesn't interest you, then you press Shift+F9 again, you have a new break with the same structure as the PUSHs that you don't care about, you keep pressing Shift+F9 until you get to the end of the loop in the offset 0x00315AB. Continuing with F8 we arrive at the classic sequence of instructions found in ASPACK:
by executing the highlighted statement by pressing F8 we have:
then proceed to the RETN and press F8. In this case, the redirection to the quarry will be done at the offset 0x00315C1 therefore:
OFFSET: 0x00315C1
ORIGINAL INSTRUCTION: POPAD/JNZ
At this point it may be useful for subsequent analysis to put a hardware breakpoint in this new entry at the 0x00289DC offset, this will in fact waste less time in case we have to reboot the program. At this point we press CTRL+B and write the following:
Press OK, the specified sequence is identified from the offset 0x0018662:
this code is related to the mapping of the file in memory through the MapViewOfFileEx invoked via emulated code (on my machine at the time of writing at 0x00A20000).
We then put the breakpoint at the entry point of the MapViewOfFileEx.
However, there are several breaks, so you have to repeat the execution until you get to the code above (using the combination ALT+M break on access in the run-time area then Shift+F9), that's where the shortcut above using binary search comes from. ASProtect, with the MapViewOfFile has created an image of the file present on disk in memory, this is used to check that the file has not been altered, for example with in-line patching, the check is related only to the file on disk since the code at the OEP has not yet been decrypted.
The offset to be patched for PUSH 4 is 0x0018669, while the redirection, immediately after the execution of the MapViewOfFile, must be done at the offset 0x001867A.
OFFSET: 0x001867A
ORIGINAL INSTRUCTION: MOV EBX,EAX
In the redirection we will use EAX right away since the contents of this register provide the base address where the image of the file on disk begins. Continuing to trace you get to the verification of error 61:
You pass it and after a bit of tracing you get to the cycle that deals with decompressing the program code.
In fact, we have in the OllyDbg dump window:
to see the updated code it is sufficient to return to the OllyDbg code window, press CTRL+G and write the address of the OEP, then force the analysis of the code by OllyDbg by pressing CTRL+A.
To be continued.....
Especially for xss.pro
In-line patching is not the easiest way to change the behavior of a program since it requires a good knowledge of the packer's operating mechanisms, but once the concepts that govern its operation have been assimilated, it can be easily extended to packers of different types.
From the point of view of efficiency it is certainly a winning technique compared to unpacking since the final patch is generally much smaller than those of the uncompressed executable, as it takes longer than unpacking.
the Chord Pickout program (version 1.5) was used
PACKER ANALYSIS (REVERSING STAGE)
Using a file scanner, the executable is analyzed to find out if it has been compressed or not.
This is confirmed by the classic structure of the entry point of the program presented by ASProtect:
As a general approach to perform in-line patching, you must first identify the OEP (or an area near it) of the application, using the usual technique of exceptions this is easily found in:
We restart the program and position ourselves in the OllyDbg dump window, press CTRL+G and write the address of the OEP 0x00499914, in this way we try to identify from which area of ASProtect memory the code that starts from the OEP is written.
The addresses all contain null bytes since the program code still needs to be unpacked from the packer stub, so we put a breakpoint on memory write in the OEP byte:
Check all the exceptions in the OllyDbg options window (ALT+O) and press Shift+F9 to start the program, OllyDbg crashes in this part of the code:
pressing F8 once executes the write loop, you have in the dump window:
To see the disassembled:
Getting:
The code is obviously not clear since OllyDbg could not have parsed it when loading the program since the code had not yet been unpacked from the packer stub so we go to the OllyDbg queue window, press CTRL+G and write the address to be parsed, then 0x00499914 and press Enter, at this point force the parsing by pressing CTRL+A:
Bingo, the code has been unzipped and matches what we found earlier by skipping the exceptions.
At this point we know that the writing of the OEP code takes place from a memory area that starts from (ALT+M to view the memory map of the running process):
This area does not belong to the sections already existing on disk since it is not contemplated in the PE-Header and is precisely an area dynamically allocated by the packer that first requests memory from the system and then fills it with the code that will then execute and that in the case analyzed takes care of decompressing the program code. Since this is an area of memory allocated at run-time, it will not be found when the program is loaded, but it will be necessary to identify when it is actually allocated in order to trace it with the in-line code. To do this we have to perform a minimum of packer reversing by identifying the sequence of dynamically allocated areas and tracking their execution with our in-line code. The first thing to do then is to find an entry point from the ASProtect stub that allows us to keep memory of the first memory allocation made by the packer, in this regard we restart everything with CTRL+F2. Let's remove all the checkmarks on OllyDbg's handling of exceptions (ALT+O to quickly access the Debugging options window) except for the first exception:
We press CTRL+G and write VirtualAlloc which is the API used to request run-time memory from the system, an API that is used by ASProtect to allocate the memory areas that will be filled with the packer code itself. Then let's put a breakpoint as illustrated below:
We press Shift+F9 and OllyDbg gets stuck in our API, we press ALT+F9 to return to the code from which the API call was made and we also take note of the address contained in the EAX:
OBSERVATION: The value 0x00B30000 assumed by EAX in general may differ from machine to machine since
turns out to be the address of a memory area allocated at run time.
The memory map of the process under consideration (ALT+M) is as follows:
As you can see, the area we saw before interested in the decompression of the code at the OEP is not yet present, this means that the area in question belongs to a layer that will be decompressed at run-time at a later time. At this point, however, we have to see if the code that calls the VirtualAlloc is already available at the time of the first loading of the program, that is, when we are in the entry point of the packer.
To do this, press CTRL+F2 to return to the entry point and then let's see what we find at the address 0x004EB4E1:
The code is different from the one seen previously, this means that ASProtect performs preliminary code decryption operations before calling the VirtualAlloc, so we have to identify where this code is written, to do this we can restart the program and put a memory breakpoint in writing at the address 0x004EB4E1 in order to identify the point where the code is actually written.
In particular, we have:
press Shift+F9 and OllyDbg locks at address 0x004EB13F, the next call, if executed by pressing F8, decrypts all the code.
Let's restart OllyDbg with CTRL+F2 and from the entry point let's see what we have at address 0x004EB142, yup, now the code is exactly what it should be so we have identified a potential entry point to be able to track the execution of the code. If you execute the code step-by-step using F7 you can easily realize that we are inside the decompression loop, I report all the code with some NOPs inserted that de-obfuscate the code itself making it clearer what the packer does, in short the various calls inside the loop are used as if they were jumps.
The only exit point of the code is at address 0x004EB1AA, so let's put a breakpoint at this point and press Shift+F9, when OllyDbg crashes we notice that the code at the destination of the JMP has changed, a sign that the decompression loop has done its job, thanks to ASProtect.
Now let's restart OllyDbg with the usual CTRL+F2 and let's go immediately to see the code at the address 0x004EB1AA:
we have the plaintext code of the jump that is made at the end of the decryption loop, very good, this can be a nice point of attack to be able to insert the first redirect to the in-line patching code, so let's take note of it:
FINE LOOP#1: 0x004EB1AA
ORIGINAL INSTRUCTION: JMP 0x004EB1CA
Once we reach the JMP, i.e. after we have completely looped, we must also check if the code at the address of the first VirtualAlloc has actually been decrypted. In this regard, we then press CTRL+G and write 0x004EB4E1, the code unfortunately has not yet been decrypted, so we proceed with the analysis of the code using the single step with F7, after a few instructions we encounter again a decryption loop with obfuscated code.
The exit from this loop is at address 0x004EB267, so we put a software breakpoint (F2) and press Shift+F9 to execute the whole loop.
As usual, we take note of the address at which the loop ends and the original instruction:
FINE LOOP#2: 0x004EB267
ORIGINAL INSTRUCTION: JMP 0x004EB290
Also in this case the new code is decrypted, as we did previously we go to see if the code at VirtualAlloc has been decrypted, also in this case it has not yet been written, so let's proceed with the single step, now we are close to the conclusion of this first phase. An additional loop is easily identified:
insert a memory breakpoint at the exit point and press Shift+F9 to loop the entire loop.
We always take note of the address and instruction at the end of the loop:
FINE LOOP#3: 0x004EB32D
ORIGINAL INSTRUCTION: JMP 0x004EB373
Let's check again if the code that takes care of calling the VirtualAlloc has been decrypted by pressing CTRL+G and entering the 0x004EB4E1 address, we are not there yet, so we must continue to trace. Let's restart OllyDbg and put the breakpoint at the end of the first loop 0x004EB1AA and press Shift+F9, then put the breakpoint at the end of the second loop in 0x004EB267 and press Shift+F9 and finally the breakpoint on the third loop in 0x004EB32D and press Shift+F9. Now we have passed all three of the first three loops, we continue to track with F7. As expected, there is a further decryption loop, this time slightly different from the previous ones and to some extent easier to analyze.
You put a breakpoint at the end of the loop and run it with Shift+F9.
FINE LOOP#4: 0x004EB410
ORIGINAL INSTRUCTION: CALL 0x004EB427
Check if the code that calls the VirtualAlloc is finally decrypted:
YEPP finally we have arrived, now the code that takes care of calling the VirtualAlloc has been decrypted.
To recap what has been done so far, the packer performs the following operations:
1. We are at the entry point in
2. The first decryption loop is performed until the output in 0x004EB1AA
3. The second decryption loop is performed until the output is 0x004EB267
4. The third decryption loop is performed until the output in 0x004EB32D
5. The fourth decryption loop is performed until the output in 0x004EB410
6. You will arrive at the address of the VirtualAlloc call in 0x004EB4E1
As a breakpoint (to be activated sequentially starting from the Entry Point and after each loop has been executed) we have:
Continuing to trace we arrive at the instructions that call the VirtualAlloc, in particular we have two calls, a loop that writes the code in the area we are interested in dynamically allocated by the second call to the VirtualAlloc and finally a jump within the new area.
The push 0BA1000 followed by the RETN jumps to the allocated area and in particular to the offset related to the PUSH 8000 instruction it is possible to retrieve in EDI the base address of the region to which it jumps once the RETN has been executed at the end of the routine. we can then use the space associated with the PUSH 8000 to redirect execution to our in-line code.
ADDRESS: 0x004EB5E8
ORIGINAL STATEMENT: PUSH 8000 -> 0x68 0x00 0x80 0x00 0x00
The execution jumps to the regions allocated by ASProtect at the 0x0031000 offset. The offset is important since the regions do not have absolute addresses in memory. We are now in the memory area that will perform the decompression of the code to the OEP.
If we look at the code at address 0x00B72663 (offset 0x002663 from the base address) we notice that the code is different from the one seen at the beginning of our analysis, this is because we have to go through additional decompression layers before the ASProtect code that takes care of writing the OEP is in plain text and is executed.
Let's resume the analysis from the 0x00BA1007 address, if we proceed step by step in the code we arrive at a further call of the VirtualAlloc in 0x00BA10C4 continuing step by step we have a write loop.
which brings us to a new leap to 0x003130D offset. Also in this case it is advisable to identify a point where we will jump to our in-line code and this can be done again by identifying the PUSH 8000 instruction so we will have:
OFFSET: 0x00310F3
ORIGINAL STATEMENT: PUSH 8000 -> 0x68 0x00 0x80 0x00 0x00
We continue the analysis of the code by tracing with F8 and checking in the OllyDbg dump window if the code at the 0x00B72663 address is decrypted, so far the code has not yet been written, so we continue with the analysis. We reach the RETN statement and press F8, at the offset 0x0031343 we have a new call to the VirtualAlloc.
Continue with F8 to the offset 0x00313C7 here is the loop that writes the part of the code that takes care of decompressing the code to the OEP. Let's mark the offset of the PUSH 8000 instruction that will be used for the next redirection:
OFFSET: 0x00313D7
ORIGINAL STATEMENT: PUSH 8000 -> 0x68 0x00 0x80 0x00 0x00
In fact, if we press F8 once and observe in the dump window set to the display of the dissasas, we have the code in plain text:
Continuing the analysis we arrive at a rather interesting block of code since it seems to have to do with the IAT, in fact two loops are identified, one external and one internal:
the decoded APIs are written starting from the offset, 0x002C104, the loop ends at the offset 0x00315AB.
If you run the whole loop you get to the breakpoint on the MapViewOfFile, you press ALT+F9, you get to a part of the code where you have three PUSHs 0 this one doesn't interest you, then you press Shift+F9 again, you have a new break with the same structure as the PUSHs that you don't care about, you keep pressing Shift+F9 until you get to the end of the loop in the offset 0x00315AB. Continuing with F8 we arrive at the classic sequence of instructions found in ASPACK:
by executing the highlighted statement by pressing F8 we have:
then proceed to the RETN and press F8. In this case, the redirection to the quarry will be done at the offset 0x00315C1 therefore:
OFFSET: 0x00315C1
ORIGINAL INSTRUCTION: POPAD/JNZ
At this point it may be useful for subsequent analysis to put a hardware breakpoint in this new entry at the 0x00289DC offset, this will in fact waste less time in case we have to reboot the program. At this point we press CTRL+B and write the following:
Press OK, the specified sequence is identified from the offset 0x0018662:
this code is related to the mapping of the file in memory through the MapViewOfFileEx invoked via emulated code (on my machine at the time of writing at 0x00A20000).
We then put the breakpoint at the entry point of the MapViewOfFileEx.
However, there are several breaks, so you have to repeat the execution until you get to the code above (using the combination ALT+M break on access in the run-time area then Shift+F9), that's where the shortcut above using binary search comes from. ASProtect, with the MapViewOfFile has created an image of the file present on disk in memory, this is used to check that the file has not been altered, for example with in-line patching, the check is related only to the file on disk since the code at the OEP has not yet been decrypted.
The offset to be patched for PUSH 4 is 0x0018669, while the redirection, immediately after the execution of the MapViewOfFile, must be done at the offset 0x001867A.
OFFSET: 0x001867A
ORIGINAL INSTRUCTION: MOV EBX,EAX
In the redirection we will use EAX right away since the contents of this register provide the base address where the image of the file on disk begins. Continuing to trace you get to the verification of error 61:
You pass it and after a bit of tracing you get to the cycle that deals with decompressing the program code.
In fact, we have in the OllyDbg dump window:
to see the updated code it is sufficient to return to the OllyDbg code window, press CTRL+G and write the address of the OEP, then force the analysis of the code by OllyDbg by pressing CTRL+A.
To be continued.....