|
|
Home » Developing U++ » UppHub » Protect package - A starting copy protection system
|
Re: Protect package - A starting copy protection system [message #49952 is a reply to message #49950] |
Wed, 06 June 2018 15:30 |
Tom1
Messages: 1242 Registered: March 2007
|
Senior Contributor |
|
|
Hi,
Every now and then I had occasional problems with ProtectEncrypt regarding both PROTECT and OBFUSCATE and the resulting executable on x64. Then I decided to disable optimizations by going from /O2 to /Od. Then both PROTECT and OBFUSCATE started to work on x64 even in my larger application.
I have now added the following pragma to all my cpp source files using PROTECT and/or OBFUSCATE and it seems to stabilize things for now:
#pragma optimize( "tsg", off )
Best regards,
Tom
UPDATE: Yes, return; does indeed still work from within PROTECT, but '#pragma optimize( "tsg", off )' is needed to avoid optimization which would break it. Do you think it would be a good idea to include this directly in <Protect/Protect.h> to avoid optimization that can break it?
[Updated on: Wed, 06 June 2018 16:02] Report message to a moderator
|
|
|
|
Re: Protect package - A starting copy protection system [message #49962 is a reply to message #49954] |
Thu, 07 June 2018 12:26 |
Tom1
Messages: 1242 Registered: March 2007
|
Senior Contributor |
|
|
Hi Max,
It seems to me that it is enough to add:
#pragma optimize( "g", off )
(i.e. disable 'global optimizations') to get the correct encryption result and working executables with MSC.
UPDATE: This is needed with both 32-bit and 64-bit MSC.
-
Encryption of large applications does seem to require 32-bit ProtectEncrypt for 32-bit executables and 64-bit version for 64 exes. It is really inconvenient to edit manually the post-link step to switch between 32 and 64-bit versions of ProtectEncrypt. Would it be possible to automatically detect 32-bit and 64-bit executables apart and use the correct mode?
Best regards,
Tom
[Updated on: Thu, 07 June 2018 12:35] Report message to a moderator
|
|
|
Re: Protect package - A starting copy protection system [message #49963 is a reply to message #49962] |
Thu, 07 June 2018 13:16 |
Tom1
Messages: 1242 Registered: March 2007
|
Senior Contributor |
|
|
Hi Max,
Here's the last stretch of ProtectEncrypt with added automatic 32/64 -bit Windows PE machine type detection and respective XED configuration. Works with MSBT17/MSBT17x64 on Windows.
Cerr() << "ENCRYPTION KEY : " << HexString(key) << "\n";
// loads file into buffer
String fName = CommandLine()[0];
if(!FileExists(fName))
{
Cerr() << "File '" << fName << "' not found\n";
return;
}
FileIn f(fName);
dword size = (dword)f.GetSize();
Buffer<byte>buf(size);
f.GetAll(buf, size);
f.Close();
#ifdef WIN32 // Tom added
int coffindex=*(unsigned int*)&buf[0x3c];
unsigned short machine=*(unsigned short*)&buf[coffindex+4];
switch(machine){
case 0x14c: //i386
Cout() << "Processing 32-bit i386 executable\n";
XED.Set32bitMode();
break;
case 0x8664: // AMD64
Cout() << "Processing 64-bit AMD64 executable\n";
XED.Set64bitMode();
break;
default:
Cout() << "Unknown executable - Cannot process\n";
return;
}
#endif
// encrypt the application
CryptBuf(buf, buf + size, key);
// save the encrypted file
FileOut fOut(fName);
fOut.Put(buf, size);
// sets up exit code
SetExitCode(0);
Please merge, if this looks OK to you.
Best regards,
Tom
|
|
|
|
Re: Protect package - A starting copy protection system [message #49967 is a reply to message #49966] |
Fri, 08 June 2018 12:42 |
Tom1
Messages: 1242 Registered: March 2007
|
Senior Contributor |
|
|
Hi Max,
Thanks!
Here's an ELF -extended version of the instruction set detection:
unsigned short machine=0; // Unknown
if((*(unsigned int*)~buf)==0x464c457f) machine=*(unsigned short*)&buf[0x12]; // ELF machine ID
else if((*(unsigned short*)~buf)==0x5a4d){ // DOS header
int coffindex=*(unsigned int*)&buf[0x3c]; // Coff header
machine=*(unsigned short*)&buf[coffindex+4]; // Machine ID
}
switch(machine){
case 0x03: // x86 ELF
Cout() << "Processing 32-bit i386 ELF\n";
XED.Set32bitMode();
break;
case 0x3e: // x86-64 ELF
Cout() << "Processing 64-bit AMD64 ELF\n";
XED.Set64bitMode();
break;
case 0x14c: //i386 PE
Cout() << "Processing 32-bit i386 COFF/PE\n";
XED.Set32bitMode();
break;
case 0x8664: // AMD64 PE
Cout() << "Processing 64-bit AMD64 COFF/PE\n";
XED.Set64bitMode();
break;
default:
Cout() << "Unknown executable - Cannot process\n";
return;
}
My Linux VM running U++ is not quite healthy at the moment, so I could not test this ELF thing immediately, but maybe you can. Anyway, the ELF header info is from:
https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
I can't show my actual code, but I'll see what I can do to demonstrate the optimization issue with a test case.
Thanks and best regards,
Tom
|
|
|
Re: Protect package - A starting copy protection system [message #49968 is a reply to message #49967] |
Fri, 08 June 2018 13:00 |
Tom1
Messages: 1242 Registered: March 2007
|
Senior Contributor |
|
|
Max,
Here's the testcase. Just replace the original 'encrypted' function with the following in your ProtectTest.cpp:
int squared(int x){
PROTECT_START_FUNC(GetCypher);
return x*x;
PROTECT_END_FUNC;
}
void encrypted(int x)
{
PROTECT_START_FUNC(GetCypher);
Cerr() << "X * X = " << squared(x) << "\n";
PROTECT_END_FUNC;
}
So, ProtectEncrypt fails in both 32 and 64 bit mode, unless you add:
#pragma optimize( "g", off )
in ProtectTest.cpp.
Anyway, note that speed and size optimizations can still remain enabled.
Best regards,
Tom
|
|
|
Re: Protect package - A starting copy protection system [message #49969 is a reply to message #49968] |
Fri, 08 June 2018 14:22 |
Tom1
Messages: 1242 Registered: March 2007
|
Senior Contributor |
|
|
Hi Max,
I finally got my Linux VM up and running again. It's Linux Mint 18.3 (a 64-bit platform). The good news is that at least ELF-64 detection now works in ProtectEncrypt.
However, it seems now that ProtectEncrypt fails with my previous testcase regardless of compiler (GCC or CLANG). Setting optimization to -O0 does not help here. I wonder if it does some automatic in-lining of functions... or something else.
Best regards,
Tom
|
|
|
Re: Protect package - A starting copy protection system [message #49970 is a reply to message #49969] |
Fri, 08 June 2018 14:41 |
Tom1
Messages: 1242 Registered: March 2007
|
Senior Contributor |
|
|
Max,
I did some quick testing on my 64-bit Linux platform with GCC and CLANG. The result is that if you change the squared function as follows:
int __attribute__ ((noinline)) squared(int x){
PROTECT_START_FUNC(GetCypher);
int rc=x*x;
PROTECT_END_FUNC;
return rc;
}
I.e. move return outside the PROTECT envelope, and add "__attribute__ ((noinline))" to avoid inlining, it will work correctly with both CLANG and GCC.
It will work correctly in CLANG without "__attribute__ ((noinline))" too, but still requires return to be outside the PROTECT envelope.
Best regards,
Tom
|
|
|
Re: Protect package - A starting copy protection system [message #49973 is a reply to message #49970] |
Fri, 08 June 2018 17:04 |
mdelfede
Messages: 1308 Registered: September 2007
|
Ultimate Contributor |
|
|
Hi Tom,
first, thank you for your code to identify executable type... I embedded it in ProtectEncrypt.
Second, about inlined functions, optimizer and protect: I think that if the function gets inlined the ProtectEncrypt will not work.
That's not for sure, but normally when a function is inlined it is also re-arranged and probably the protect headers and trailers
go out of sync.
Calling an inlined function from inside e protect block SHOULD work, and also the embedded return should do no harm.
I will test your example to see what happens; mostly the return is replaced by compiler with a jmp to code end, but sometimes the code gets re-arranged by the optimizer. I tried my best to avoid it using volatile data inside dummy calls, but it still may happen.
BTW, I'm still not receiving forum notifications... not for private messages, either.
Probably my account is old and the forum software has some bugs, I don't know.
Ciao
Massimo
|
|
|
|
Re: Protect package - A starting copy protection system [message #49979 is a reply to message #49978] |
Sat, 09 June 2018 09:49 |
Tom1
Messages: 1242 Registered: March 2007
|
Senior Contributor |
|
|
Hi Max,
It might be safest to just document that 'No returns allowed within PROTECT or OBFUSCATE sections.' It is not very difficult to collect the return codes to the end of the function into a single return statement. That's the way I solved the issue in my code anyway.
Inlining of protected functions must be prevented though, because that will in effect create a PROTECT section within another PROTECT section when both functions are protected.
Best regards,
Tom
|
|
|
|
Re: Protect package - A starting copy protection system [message #49989 is a reply to message #49981] |
Tue, 12 June 2018 20:23 |
Tom1
Messages: 1242 Registered: March 2007
|
Senior Contributor |
|
|
Hi Max,
Sorry for the delay, I'm really busy at work now.
I see your point. I guess there's no way to go around that with e.g. any dummy addition to PROTECT_END_FUNC either. The simplest way for me was to collect the return value to a variable along the way of execution of function and then return that value in the end after PROTECT_END_FUNC. Everything appears to be working with my code, so it's all good now!
I feel you have made great job with this new version of Protect! Thank you very much Max!
Best regards,
Tom
|
|
|
Goto Forum:
Current Time: Sat Sep 21 06:27:26 CEST 2024
Total time taken to generate the page: 0.03586 seconds
|
|
|