Link to home
Start Free TrialLog in
Avatar of Evarest
Evarest

asked on

Secure code for Delphi apps

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
Avatar of DavidBirch2dotCom
DavidBirch2dotCom

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
Avatar of Evarest

ASKER

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
lol well I tried ;)

David
SOLUTION
Avatar of BdLm
BdLm
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Avatar of Wim ten Brink
Wim ten Brink
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Evarest

ASKER

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
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Evarest

ASKER

>> 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?
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.
wow this is complex *looks scared*
Avatar of Evarest

ASKER

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
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. :)
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 ...