Perhaps I should provide you with detailled information regarding Safedisc.

First, to determine the Safedisc version, you have to search for this string in the executable : "BoG_ *90.0&!!  Yy>", after there are 3 unsigned longs, that are the version, subversion and revision numbers. The wonderful Thief 2 1.18 is 1.41.00.

Note that I do not consider anti debugging features here, I am only writing about unwrapping. Watch out your debug registers !

1.0.0 : first version of Safedisc. Sections are ciphered using the TEA algorithm with a 128 bits key of the form aaaa where a is a 32 bits number. The key is red from the CD or computed from hidden data in the loader if this is impossible (CD reader failure). The imports are simply mixed using a Monte Carlo algorithm, you need to demangle them with the TEA key and then update the first thunk. Note that only kernel32.dll and user32.dll are "mangled".

1.7.0 : There is an additional step to perform prior to reorder the imports, you have to decrypt the ASCIIs, the algorithm is actually quite simple, you also have to remove the "hint".

Here is the algo used to decipher the ASCII (taken from Safedisc annihilator) :

// key is the 128 bits TEA key
ascii_key = (unsigned char)((key >> 24) ^ 0xAB); // will be needed to decipher the ASCII

for(k = 2, cur_ascii_key = ascii_key; ; k++)
{
  buffer = ascii_pointer[k];
  ascii_pointer[k] ^= cur_ascii_key; // xor character using key
  cur_ascii_key = buffer; // key is unxored character

  if (ascii_pointer[k] == 0)
    break;

} // end ascii deciphering

1.30.0 : Now the imports' RVAs are xored using the lower 32 bits of the TEA key, this helps you to quickly find the TEA key (an idea of Black Check). Why ? Simply because of the missing imports are stored in loader.exe (you will find 4 dwords in the loader in this form a a b b just after a 0x00000000), and instead 0x00000000 is stored in the imports. If we xor the ciphered 0x00000000 with one of the dword found in the loader, we will obtain the TEA key (well the lowest 32 bits dword, but since the key is of the form aaaa, you can extrapolate the full key most easily) ! All you have to do is to try for each import dword.

1.40.4 : Things are becoming more complicate here, and I think this is what caused you a problem. Now the calls (well, a certain kind of call only, C-dilla did not implement a disassembler in Safedisc !) are modified and need to be fixed. Here is the solution R!SC found and that I also used (this is actually a mimic of Safedisc) :

- look for 0xff15 in the code section(s)
- compute a "remainder" (the way it is computed will change in other version). This remainder is the way C-dilla found to apply their algorithm only on calls. Pretty lame I must say.
- If the remainder  is equal to a certain value (again this changes), then proceed with "deciphering".
- "Deciphering" pseudo code :
  - determine if this is a call to user32 or kernel32
  - call_pointer -= api_thunk_start
  - call_pointer += (current_section_offset + key) % number_of_apis
  - call_pointer = (call_pointer + number_of_apis) % number_of_apis
  - call_pointer = (call_pointer << 2) + api_thunk_start + pe_image_base

Yes, I know this is a hack, but this is the way it is done in Safedisc.

1.41.0 : The only change here is that the calls remainder is computed in a different fashion.

1.45.11 : Things changed here. Sound like C-dilla found out about our generic unwrappers. ;-) Well they did two things to counter us (but it did not work of course).

Problems :
1/They fixed the TEA key weakness (the fact that it is 4 times the same dword), the key is now a real 128 bits number (do not worry we found a way around).
2/To prevent automatic unwrapping, they use code inside dplayerx.dll for the calls "stuff". This code changes with every protected program, and thus you cannot write a generic algorithm (again, we found a way around :-).

Solutions :
1/Well, I do not like to despise other programmers' work, but this move was pretty worthless. At first we were a little bit concerned by this, but eventually someone (I think it is r!sc) discovered that the 128 bits key is actually computed from various values we can easily retrieve (instead of reading 128 bits from the CD, which would have been more secure...).

Using our magic 32 bits value :
 inc_entry_point = entry_point + 0x2d8; // entry_point is the icd entry point

 x_val = ((TEA_key1 - inc_entry_point) ^ checksum) ^ raw_key[0];
 full_TEAkey[0] = TEA_key1;
 full_TEAkey[1] = (x_val ^ raw_key[1]) + inc_entry_point;
 full_TEAkey[2] = (x_val ^ raw_key[2]) + inc_entry_point;
 full_TEAkey[3] = (x_val ^ raw_key[3]) + inc_entry_point;

The raw key is stored in loader.exe, look for "DECRPE\0\0". In future version they added an offset, but it is still located in the same place.

Another result of this feature is that we started to wonder if there was actually any data red off the CD. I knew there was some data actually red from the CD (this was partially correct), but later I learnt that this data is also present in the loader (to make the protection work on poor CD readers), which means that you can generate the full key without any brute forcing and without the original CD.

2/Well, this was a more clever move. I had to implement a dplayerx.dll loader (and had to fight against some nasty problems under 2k), get the pointer to the "magic routines" and apply them. Note that the call "deciphering" routine is still the same (logical), this is the way used to determine if a call must be fixed or not that changed. It is not a remainder any more, we apply a "eax modifier" (a routine that modifies the value of the eax register) stolen from dplayerx.dll. This is the only reasonable way, since the "eax modifier" changes with each different dplayerx.dll.

1.50.20 : One big new feature here, a second layer of encryption is applied on the ICD using a mundane algorithm. Also the address for the dplayerx.dll routines changed. The second layer of encryption has to be removed before brute forcing of course. And yes, the second layer uses a routine from dplayerx.dll. Here is the algorithm for a block of data :

bool __fastcall icd_rebuilding::new_decipher_block(void *p, unsigned long size)
{

  unsigned long done, i_size;
  unsigned long buf1, buf2;
  unsigned long *ptr;

  done = 0;

  i_size = size >> 2;

  ptr = (unsigned long *)p;

  while(done < i_size)
  {
    buf2 = (done << 0x18) | (done << 0x10) | (done << 0x08) | done;
    buf1 = ptr[done] ^ buf2;
    buf1 = m_dplayerx->execute_eax_modifier(0x65be, buf1) ^ buf2;
    ptr[done++] = m_dplayerx->execute_eax_modifier(0x65be + 0x63, buf1);
  }

  return true;

}

2.05.30 : Ahaha, Safedisc 2.
What changed ? From the outside, many things have changed.
Internally ? Nothing.

2.05.30 from an unwrapping point of view is strictly 1.50.20. What is boring though is the anti-debugging features payload, which is heavier. Also everything is now packed in one executable. You need to extract the data from this executable to work. It is appended at the end of the executable.
Since I have not really worked on Safedisc 2, I cannot tell you the exact nature of the algorithms, but I suspect them to be quite simple. Portia posted about them on my messageboard, but I have discarded the message.

To unwrap 2.05.30 you have to do the following :
 - extract dplayerx.dll and the "loader" from the main executable.
 - the main executable is now the icd file. Unwrap the sections, except the stxt774 and stxt371 ones which were added by Safedisc2.
 - fix the entry point (it points to Safedisc code). The original entry point is hidden "under" the main SD2 routine, it is very easy to find with IDA.
 - remove the SD2 garbage.

There are also more recent version of Safedisc 2 available, but I have stopped working on Safedisc since 2.05.30 (lack of motivation). I would appreciate that someone posts additional information on my message board. I think I am going to work again of Safedisc Annihilator. I am tired of downloading cracks just to play without the CD, this is unl33t. :-)

If you find information about Safedisc hard to come by, this is because of the bad spirit of competition in the warez scene. Some crackers are sharing their knowledge only with the members of their group. I do not think they realize that everybody would benefit from cooperation.

"He who controls the unwrapping controls the warez". ;-)

I hope this was helpful, but if you ask me you will have more fun playing Thief 2 (do not forget the patch, very important). Use my Safedisc Annihilator 1.1 to unwrap it, if you want to play without the CD you will have to perform a full install and to do a simple crack (GetDriveType() && GetVolumeInformation()).




