Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » Developing U++ » UppHub » Protect package - A starting copy protection system
Re: Protect package - A starting copy protection system [message #49951 is a reply to message #49950] Wed, 06 June 2018 15:27 Go to previous messageGo to next message
mdelfede is currently offline  mdelfede
Messages: 1307
Registered: September 2007
Ultimate Contributor
Hi Tom,

PROTECT should work also with a return inside the encrypted code... if not, it's possible that the compiler re-arrange the code in some weird way. You should activate debugging both on encrypter and on protect and look what happens.

OBFUSCATE doesn't work with an embedded return, for 2 reasons : first, it uses a Mutex on enter and frees it on exit, and the embedded return misses the mutex release; second (and most important) the end part re-encrypts the code, and must be executed when the function exits.

If you've got some code that makes troubles with both protect or obfuscate please run it activating the 2 debug #define and post it the results... and maybe the encrypter log too.

Ciao

Max
Re: Protect package - A starting copy protection system [message #49952 is a reply to message #49950] Wed, 06 June 2018 15:30 Go to previous messageGo to next message
Tom1
Messages: 1212
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 #49954 is a reply to message #49952] Wed, 06 June 2018 17:19 Go to previous messageGo to next message
mdelfede is currently offline  mdelfede
Messages: 1307
Registered: September 2007
Ultimate Contributor
Tom1 wrote on Wed, 06 June 2018 15:30
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.



This is probably caused by code rearranged by the optimizer... my code requires that the closing macro code comes AFTER the opening one, inside the executable. If the optimizer swap stuffs it doesn't work

Quote:

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 )



you should try disabling single optimizations up to it works. Normal optimizations should be harmless.
My code is quite complex and on GCC works correctly. I still have to test it on MSC, but then only on 32 bit... I don't do 64 bit builds for MSC.

Quote:

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?


Maybe that's a good idea. We should try to find the right optimizations... it would be a pity to disable all of them.
Re: Protect package - A starting copy protection system [message #49962 is a reply to message #49954] Thu, 07 June 2018 12:26 Go to previous messageGo to next message
Tom1
Messages: 1212
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 Go to previous messageGo to next message
Tom1
Messages: 1212
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 #49966 is a reply to message #49963] Fri, 08 June 2018 11:57 Go to previous messageGo to next message
mdelfede is currently offline  mdelfede
Messages: 1307
Registered: September 2007
Ultimate Contributor
Hi Tom,

patch applied!

Still not sure if apply the optimization patch.
Do you have a (short) example showing that the encrypter doesn't work with optimization enabled ?

Ciao

Max
Re: Protect package - A starting copy protection system [message #49967 is a reply to message #49966] Fri, 08 June 2018 12:42 Go to previous messageGo to next message
Tom1
Messages: 1212
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 Go to previous messageGo to next message
Tom1
Messages: 1212
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 Go to previous messageGo to next message
Tom1
Messages: 1212
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 Go to previous messageGo to next message
Tom1
Messages: 1212
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 Go to previous messageGo to next message
mdelfede is currently offline  mdelfede
Messages: 1307
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 #49978 is a reply to message #49968] Fri, 08 June 2018 23:44 Go to previous messageGo to next message
mdelfede is currently offline  mdelfede
Messages: 1307
Registered: September 2007
Ultimate Contributor
Hi Tom,

Tom1

Here's the testcase. Just replace the original 'encrypted' function with the following in your ProtectTest.cpp:
[code
int squared(int x){
PROTECT_START_FUNC(GetCypher);
return x*x;
PROTECT_END_FUNC;
}

[/code]


This happens because the compiler removes ALL the code after the return statement, as it would be never executet.
I'm trying to find a workaround, but I guess it'll be not an easy task...
Re: Protect package - A starting copy protection system [message #49979 is a reply to message #49978] Sat, 09 June 2018 09:49 Go to previous messageGo to next message
Tom1
Messages: 1212
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 #49981 is a reply to message #49979] Sun, 10 June 2018 21:19 Go to previous messageGo to next message
mdelfede is currently offline  mdelfede
Messages: 1307
Registered: September 2007
Ultimate Contributor
Hi Tom, the problem is NOT the return inside protect, just a return with nothing after.
The compiler just removes ALL code after last return, because it doesn't get executed.
it should work, for example, in this case:
int encrypted(int x)
{
    PROTECT_START_FUNC(GetCypher)
    if(x == 2)
        return 2*x;
    PROTECT_END_FUNC
    return 3*x;
}

But NOT in this one:
int encrypted(int x)
{
    PROTECT_START_FUNC(GetCypher)
    if(x == 2)
        return 2*x;
    return 3*x;
    PROTECT_END_FUNC
}
Re: Protect package - A starting copy protection system [message #49989 is a reply to message #49981] Tue, 12 June 2018 20:23 Go to previous message
Tom1
Messages: 1212
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
Previous Topic: UPDATED PROTECT PACKAGE
Next Topic: OAuth2 package for U++
Goto Forum:
  


Current Time: Thu Mar 28 20:34:27 CET 2024

Total time taken to generate the page: 0.01386 seconds