Log in

View Full Version : Weird tamper detection


naides
October 5th, 2006, 10:13
Ok. I need a little help from my friends with this one.

Some App protection is contained in a someapp.dll.
Actually, most of the app workings are in this someapp.dll, and the main exe acts mostly as a loader.

Reversing the app by patching the someapp.dll was not trivial, but not impossible.

the problem is that the protection detects any change I do into the someapp.dll file in disk. When the file has been modified, even by a single byte, the code goes into an impassable exception. When that happens, there are no tracks in the call stack or the actual stack on what or where in the code the exception was generated.

Even changing a single byte in the header string "This program cannot be run in DOS mode" makes the app throw a fit and and produce the exception.

My problem is catching the code that checks the integrity of the someapp.dll. I know that the code does not check other files for integrity. gross changes in other dlls do run seamlessly.

The dll is not loaded by the main module at the entry point. it is laoded later, by calls to LoadLibrary api. I have stop the program right when the module is loaded, and put a hardware breakpoint to the byte I changed, but apparently, the detection takes place before the library is loaded, because the memory break point does not break, yet the protection detects the one byte change.

I have compared the code flow between a modified someapp.dll and the original someapp.dll by placing a bp at the dll entry point. early in the execution, the code calls the API MSVCR71._initterm: This API systematically runs through a list of calls, calling hundreds of functions within the someapp.dll code. One of them throws the exception in response to file tampering. I isolated the call that crashes the modified version of someapp.dll.

I traced the fateful call in modif and unmodif verions of the .dll and I found that a call to kernel TLSGetValue, with an index of 0x18 pushed into the stack, returns 00000001 in the good version of someapp.dll, and 00000000 in the the bad, modif version of someapp.dll, which directs a conditional jump into the fatal exception.


mine has been a rather convoluted route to find this out. My questions to the experts are:

How can I catch the code that is setting this flag at the TLS? I have placed memory bp on the location of the TLS but it deceives OLLy: the TLS address is "not predictable" by olly in successive runs of the program.

Needless to say, more trivial approaches like bp on createFileA or other API that read someapp.dll from disk for integrity test have produced no results, I have been unable to catch the actual integrity test process in memory or in disk.


I can post the name of the commercial protection in here, but I have not seen anyone mentioning it before, and I am not sure this tamper detection is home made or part of the commercial package. If you want to take a look at the app,

please PM me.

Kayaker
October 5th, 2006, 10:30
Hi naides,

What do breaks on TlsAlloc and TlsSetValue (index 0x18) expose, both supposed requirements for using TLSGetValue?

Maximus
October 5th, 2006, 12:11
checked _lcreat?

SiGiNT
October 5th, 2006, 22:42
Just for giggles try this trick - change something in the header that you mentioned then compensate for the change elsewhere (checksum wise) - for instance change the "D" in DOS to an "E" then change the "S" to an "R" - not an answer to your question but a longshot solution to the problem - this has worked for me more than once.

Another BP to try is CreateFileMapping

SiGiNT

naides
October 6th, 2006, 19:51
With the guidance of all the people that answer the post (Thank you!)
and ZaiRon who was kind enough to take a look at the program I finally got an idea of the tamper check using the all too well documented API :

; IMAGEHLP.MapFileAndCheckSumW

Go figure.

I finally made some sense of the use of TLS in multi thread environments.

Thank you for your patience.

Maximus
October 7th, 2006, 09:47
eheh you didnt say it had the checksum set in the PE

ZaiRoN
October 7th, 2006, 09:52
Yes Maximus but he said: "Even changing a single byte in the header string "This program cannot be run in DOS mode" makes the app throw a fit and produce the exception."

Maximus
October 7th, 2006, 19:27
yep, right

Kayaker
October 8th, 2006, 00:54
So why didn't a break on CreateFileA work? It's called by MapFileAndCheckSum. Aren't kernel32.dll bp's in both SoftIce and Olly global in context?

All the dll's (someapp.dll, Imaghlp.dll,..) and the exe should be using the same mapped kernel32 image should they not, therefore a bp on a kernel32 API should be global to all and "stick" for all...?

ZaiRoN
October 8th, 2006, 07:29
Breakpoint on CreateFileA function works under both softice and ollydbg; I didn't notice it before because I found CheckSumMappedFile using a breakpoint on another function.
Maybe Naides was able to bp on CreateFile but unable to find the MapFileAndCheckSumW...

blabberer
October 8th, 2006, 07:36
is MapViewOfFile really needed ? or can it be done without calling CreateFile?

anyway one more way may be using LoadLibraryEx and calling the internal function ChecksumMappedFile

Code:

76CACEB8 6A 01 PUSH 1
76CACEBA 6A 00 PUSH 0
76CACEBC 68 E0EECA76 PUSH imagehlp.76CAEEE0
76CACEC1 E8 7B0A1D01 CALL kernel32.LoadLibraryExA
76CACEC6 68 60EECA76 PUSH imagehlp.76CAEE60
76CACECB 68 B0EECA76 PUSH imagehlp.76CAEEB0
76CACED0 68 00600E00 PUSH 0E6000
76CACED5 50 PUSH EAX ; kernel32.77E600F8
76CACED6 E8 FF6FFEFF CALL imagehlp.CheckSumMappedFile

76CAEE00 6B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 00 00 kernel32.dll....
76CAEE10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
76CAEE20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
76CAEE30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
76CAEE40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
76CAEE50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
76CAEE60 CC 9A 0E 00 00 00 00 00 00 00 00 00 00 00 00 00 虤.............
76CAEE70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
76CAEE80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
76CAEE90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
76CAEEA0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
76CAEEB0 D3 7E 0E 00 00 00 00 00 00 00 00 00 00 00 00 00 觺.............

77E60150 D37E0E00 DD 000E7ED3 ; CheckSum = E7ED3



naides
October 8th, 2006, 20:12
Actually, CreateFileA did break. But it broke very many times and it was not simple to trace back to the code that made the call. In retrospect a bp on CreateFileA would have worked also, now that I know the right area of the code.