Solved

Secure code for Delphi apps

Posted on 2004-08-02
13
1,335 Views
Last Modified: 2010-04-05
Hi,

I've been wondering about the safety of in Delphi written Applications for some time. Of course, much, if not all, of the safety of one's applications comes from the code you write... However, I've some direct questions how to prevent certain security leaks in one's programs:

1) Buffer overruns
How to prevent these? How to recognize whether some code is free of buffer overruns? Where should one be more careful about _not_ placing code that's liable to buffer overruns (ie. i mean: are internal procedures also liable to these buffer overruns, if they're for example declared as private?)

Example:
type
 PMyRecord = ^TMyRecord;
 TMyRecord = record
   str: string;
   name: string[32];
   length: integer;
 end;

procedure MyFunction( const MyRecord: PMyRecord );

This code isn't safe, is it? If I put the length of "str" in "length", is it then safe?


2) Disassembling
I've heard that Delphi Apps are easy to disassemble. At least, you get a lot of clues where you need to start disassembling (for example: if you want to find the registration key of some program, you'd rather want to start your search in the procedure DoRegister then anywhere else).

Is there a way to prevent/make it more difficult to disassemble code, apart from using strange names for your procedures?


3) Passwords:
Another issue is storing passwords. Is there any secure way to store a password you need to enter your application? For example: a user needs to give in a password to maximize the main window. How to store that password?


4) Prevent closure:
Zonealarm is able to make it quite difficult to close from the Tasklist. Just try it, and you'll find that it won't close...
Is there any way to make it more difficult for malisious users to close your application (for example: if your app is monitoring the computer). Of course, Windows should be able to close it when the computer is being shut down.

However, if Windows can close it, isn't it possible for others to close it as well, by sending the correct Message?


A lot of questions, and i've got some more, but it's a starters...

I hope you'll be able to give some answers to these questions.

Thanks,
Evarest
0
Comment
Question by:Evarest
  • 4
  • 3
  • 3
  • +2
13 Comments
 
LVL 7

Expert Comment

by:DavidBirch2dotCom
ID: 11692342
I can help with point 2)

An excellent resource to stop your exes from being disassembled/cracked is

http://www.inner-smile.com/nocrack.phtml

there are a huge number of tips on how to avoid having your exes cracked, a good discussion thread and many links to more information.  The easiest way to avoid cracking is to before distribution spend an hour or so using find and replace on a copy of the code and changing all varible names to meaningless garbage - or take every 6th word in the dictionary ;)  play with thier mind !

I can find you some more resources if necessary, but that is the most comprehensive I have found

David
0
 
LVL 4

Author Comment

by:Evarest
ID: 11692428
Thanks for the tip David, but that site i've already read some times :-) I've implemented some of the tips in my projects. For example: "Special on Delphi Reverse engineering" was quite interesting, and it shows that Delphi tend to hand crackers some interesting points to start their search...

On the topic of disassembling code: is it worthwhile to use protection s.a. Armadillo (which seems to have gone down)?

[quote]
The easiest way to avoid cracking is to before distribution spend an hour or so using find and replace on a copy of the code and changing all varible names to meaningless garbage - or take every 6th word in the dictionary ;)  play with thier mind !
[end quote]

Indeed, together with RTTI concept that tends to be an interesting course. However, doing this made my application not easier to read, especially if you're "out" of the code (didn't update it for some time)...

Evarest
0
 
LVL 7

Expert Comment

by:DavidBirch2dotCom
ID: 11692448
lol well I tried ;)

David
0
 
LVL 8

Assisted Solution

by:BdLm
BdLm earned 75 total points
ID: 11693497
#2, #3 :
the strongest protection against spyware and code protection acc. my information was given by

Sospita
A high security anti-piracy tool, preventing illegal use of intellectual property through execution of protected code in a secure environment.
http://www.sospita.com


(but i could not reopen this page today)
http://www.lukol.com/Top/Computers/Security/Products_and_Tools/Software_Protection_and_License_Control/
0
 
LVL 17

Accepted Solution

by:
Wim ten Brink earned 300 total points
ID: 11693752
1) Buffer overruns
Buffer overruns are just a problem with most Intel-based programming since data is pushed to the stack, and if you push a bit too much, you might overwrite some important value within the application. Best way to get around this is by using pointers (Or the const/var/out specifiers with parameters because then pointers will be passed too) or by checking the lengths of string values. However, Delphi seems to be pretty solid when it's about buffer overruns and the language itself makes them pretty rare anyways.

2) Disassembling
Any executable can be disassembled. But using strange names for procedures won't make it any harder because Delphi doesn't put procedure names inside the executable. But the RTTI information can provide these names again. If you use forms, then the form methods can be found, though. But there isn't much that can be done about this anyway.
To make things a bit more difficult, especially with DLL's, is using interfaces. You can make a shared unit with an interface like this:

type
  IMyInterface=interface
    procedure1(Value: shortstring);
    procedure2;
    function1: Boolean;
  end;

and then you define a single method in your DLL called NewMyInterface that returns an object of type IMyInterface. Your executable just calls this method to retrieve a value for the interface and then it's able to call all the methods in your interface. If people start debugging your DLL they just see one method that returns something but the debug information doesn't display what kind of type it is. Only that it's a pointer to something. Thus, it is less clear what they are dealing with.
Even if they suspect it's an interface, they still have to find out the exact layout of this interface, which is a lot harder. Especially if there's no type library...

3) Passwords:
Password should never be stored in the first place. All you do is calculate a hash over a password and store the hash value. This hash value can then be published all over the internet for all you care because well... A hash is a one-way operation. You cannot calculate the password back from a hashed value. You can only attempt to guess the password. Pretty safe, depending on the hashing algorithm you use. The SHA hash is pretty popular but outdated. There are better ones these days.
Of course it is important that no one can alter the hashes in your system. You must also make sure that any network connection will send the hash over in a secure (encrypted) method because there could be a sniffer in-between trying to capture the result from the sending of the hash value. If they know the result for a specific hash, they could try to break into the system with this response.
It's not very easy though.
If network traffic is required for password validation, consider using a double hash option. First the user tells the server that it wants to log in as user X. The server then returns some random key value (e.g. a GUID) and the client will have to calculate a hash over the password, then calculate a second hash over the hashed value with the additional key. The server knows only the hashed value but can also calculate this second hash by doing the same calculation. So you get:
* Server: Generate Key; Hash(StoredHash+Key);
* Client: Hash(Hash(Password)+Key);
* Then check both double-hashed values. Since the key is unique every time, it is even more harder to crack. (But it can still be cracked.)

4) Prevent closure:
You can prevent closure by creating a special system service that will restart an application whenever it notices it has been closed. I did find several ways to close applications that weren't supposed to be closed, just by telling the taskbar to debug them instead of closing them. This often resulted in a general protection error, closing the application. It is also possible to create a tool that sends a message to applications telling them Windows is closing down, thus they too close nicely. And there are a few more tricks.
But you might prefer to restart closed applications instead of preventing closure. They might close for any reason so basically they must go back alive again.
But important processes should be system services anyway, since these run in a more protected environment, away from the default user.
0
 
LVL 4

Author Comment

by:Evarest
ID: 11694419
Thanks for your comments! It's really an interesting part of programming: security...

As you seem to know so much about it, maybe i might ask you about good resources for the issues i'm posing here. I've already implemented your tip about hashing (thanks!), but i'd rather have some more info about Interfaces before i'm going to use them extensively in my code (i've never used interfaces before...)

About the buffer overruns:
when i use the procedure MyProc(aParam: string) where a param can be anything (long or short). Is this a potential target? Also, if i use messages to send entire Objects between applications which control both applications, can this be (easily) exploited?

I might getting somewhat paranoid, but these days there seem to be a lot of guys out there who don't have anything else to do but to search for such flaws in code...

Thanks in advance!
Evarest
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 7

Assisted Solution

by:sftweng
sftweng earned 75 total points
ID: 11694711
It is a very good idea to turn on runtime error cheking for your project:

Project -> Options -> Compiler -> Runtime checking.

Strong type checking in the Pascal family of languages (of which Delphi Object Pascal is one) goes a long way to avoiding security problems like buffer overruns. You should also avoid dangerous typecasting, forcing the system to treat an object as something it isn't. use the "is" and "as" operators in preference to a forcing typecast like TDangerousType(someInnocentData). Try "someInnocentData as TDangerousType" instead.
0
 
LVL 4

Author Comment

by:Evarest
ID: 11695112
>> use the "is" and "as" operators in preference to a forcing typecast like TDangerousType(someInnocentData). Try "someInnocentData as TDangerousType" instead <<

What is different to the as and 'normal' typecasting?
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11695581
The "as" does an implicit "is" and raises an exception if the type is not supported. The hard way (TMyType(MyData) doesn't do any type-checking and might let your application crash if used in the wrong way.
Strong type checking does limit the errors you can make in your application but if you create a DLL that's part of a bigger system, someone might build code that calls this DLL and calls it with invalid parameters to generate these buffer overruns. But Delphi is a lot less vulnerable for things like assigning a huge string of 20.000 to a shortstring that can only have 255 characters. Delphi does a few more checks internally, preventing many overrun possibilities. (Which is why Delphi is about twice as slow as C++ in string-handling.)

About interfaces, there's not much to tell about them. All I can say is: experiment with them.

Basically, an interface is a template. An object that supports an interface supports all the methods inside the interface, in a complete identical definition. An example from a project I'm working on right now:

[Shared unit]
type
  IDevice = interface( IUnknown )
    function GetDeviceStatus: TDeviceStatus; safecall;
    function GetDisplayName: string; safecall;
    function GetIndex: TDeviceID; safecall;
    function GetName: string; safecall;
    function GetNumber: string; safecall;
    function GetPhoneLocation: TPhoneLocation; safecall;
    function GetPhoneType: TPhoneType; safecall;
    procedure SetDeviceStatus( Value: TDeviceStatus ); safecall;
    procedure SetDisplayName( const Value: string ); safecall;
    property DeviceStatus: TDeviceStatus read GetDeviceStatus write SetDeviceStatus;
    property DisplayName: string read GetDisplayName write SetDisplayName;
    property Index: TDeviceID read GetIndex;
    property Name: string read GetName;
    property Number: string read GetNumber;
    property PhoneLocation: TPhoneLocation read GetPhoneLocation;
    property PhoneType: TPhoneType read GetPhoneType;
  end;

[DLL]
type
  TDevice = class( TInterfacedObject, IDevice )
  private
    FDeviceStatus: TDeviceStatus;
    FDisplayName: string;
    FIndex: TDeviceID;
    FNumber: string;
    FPhoneLocation: TPhoneLocation;
    FPhoneType: TPhoneType;
  protected
    function GetDeviceStatus: TDeviceStatus; safecall;
    function GetDisplayName: string; safecall;
    function GetIndex: TDeviceID; safecall;
    function GetName: string; safecall;
    function GetNumber: string; safecall;
    function GetPhoneLocation: TPhoneLocation; safecall;
    function GetPhoneType: TPhoneType; safecall;
    procedure SetDeviceStatus( Value: TDeviceStatus ); safecall;
    procedure SetDisplayName( const Value: string ); safecall;
  public
    constructor Create( AIndex: TDeviceID; const ANumber: string; APhoneLocation: TPhoneLocation; APhoneType: TPhoneType );
    destructor Destroy; override;
  end;

And I have some method in the DLL that's like:

function NewDevice(AIndex: TDeviceID; const ANumber: string; APhoneLocation: TPhoneLocation; APhoneType: TPhoneType):IDevice;

This method is called from the executable thus the executable sees only the methods and properties the interface provides. The DLL has more internal knowledge, though. This method serves multiple purposes. First of all the device becomes more abstract for whomever is working on the executable. They can't change certain values and are forced to use it in a predefined way. Second of all, you cannot determine the layout of the interface by using a debugger or other tool to examine the contents of it all. And TTI information? Interfaces don't have any. Objects do, though so once you get the object behind the interface, you can continue to debug. But getting there iis not easy.

This technique is the first step towards the use of COM and DCOM. A good book about this or any site about COM with Delphi can provide you the information you need. But the best way is just by experimenting by yourself. Before I learned about interfaces I just wondered why I would ever need them. These days most of the time I spend is by designing interfaces because of the abstraction it allows me to put in my code.

But another interesting reason for me to use interfaces is the automatic garbage collection. I can make an interface object and pass it along through all functions and procedures that are in it and don't have to worry about when I need to free it. It frees itself when no variable is looking at it anymore. No more worries about when to free it or even where. It just frees itself...

But if you care about security, then interfaces do obscure your code in quite an interesting way.
0
 
LVL 7

Expert Comment

by:DavidBirch2dotCom
ID: 11695657
wow this is complex *looks scared*
0
 
LVL 4

Author Comment

by:Evarest
ID: 11696081
Thanks Workshop_Alex for your answers and the others for their suggestions!

I've split the points accordingly, as it seemed fair in my opinion. I hope everyone's happy about it :-)

Evarest
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11714856
LOL@DavidBirch2dotCom. Yes, it looks complex at first but that might be because you're unfamiliar with interfaces. Once you're used to them, they're a real blessing in many cases, if you know how to use them correctly. Even better, as an experienced developer I can write classes this way that can be used by my less experienced collegues without having to worry about them messing things up too much. All they get from me are variables of some interface type, never of some class type. So the garbage collector will handle their sloppy code writing pretty well...

Actually, I've even made some list interfaces that contains a list of those IDevice interfaces you saw above. This list actually has an Add method that wants some parameters to create an IDevice object that is added to the list and a reference is returned as the function value. That way, the user can only create devices if they're part of the list. They can do with these devices whatever they like but they can never free the device unless they delete it from the list again. (Because the list makes sure their reference count stays minimum on 1) Thus they can send over devices from procedure to procedure, change anything that's not readonly. They just can't free it... Even after the device is deleted from the list, it isn't freed immediately. It's freed only after it's not in use anymore.
Very, very useful since you don't have to wonder about when you need to free it.

And confusing for hackers. Interfaces aren't easy to debug...

And the points are divided perfectly in my opinion. :)
0
 
LVL 8

Expert Comment

by:BdLm
ID: 11723972
BWT:  are things getting worse thinking of Delphi .Net, now i going to deliver Byte Code to my customer
and all my IP will be visible, once he can understand the class groupings within my code ...
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now