Wednesday, 12 December 2007

Not so Static Classes?

A colleague of mine noticed something interesting whilst working with C# the other day.
He had a breakpoint in a static constructor (on a non-static class) which seemed to be hit several times during execution of his program.
He discussed this with me and we both agreed that in C# it should not be possible for a static constructor to be invoked more than once in the same AppDomain, contrary to the behaviour he was experiencing.

I consulted MSDN, and found the following definitions:
Static Classes [C#]
"Static class members can be used to separate data and behavior that is independent of any object identity..."
"Static classes are loaded automatically by the .NET Framework common language runtime (CLR) when the program or namespace containing the class is loaded."

Static Constructors
"A static constructor is used to initialize any static data, or to perform a particular action that needs performed once only. It is called automatically before the first instance is created or any static members are referenced."

My colleague was working with .Net 3.0 using a class that derived from ClientBase in the System.ServiceModel namespace.
Basically, he added a static constructor to define a single EndPoint for all the instances of this derived ClientBase(T).

Upon further inspection, we saw that what was actually happening was that the Assembly containing the derived class was being loaded and instantiated by WCF using Reflection.

With this in mind, I decided to go back to basics and create a simple program to see whether there was a difference in the behaviour of static classes and static constructors when working with an Assembly loaded using Reflection.

I created a new C# solution that contained a Console Application called Demo and a Class Library called ReflectedAssembly.

1. Demo
In Demo, I added a static class called MyStaticClass.
To this class I added a static constructor and a public static method called Call which had a string parameter.
When Call is invoked, it will write the string parameter to the Console.
In the static constructor, I added a call to the Call method, passing "cctor" as a parameter.

2. ReflectedAssembly
I added a reference from ReflectedAssembly to Demo.
I added a class named ReflectedClass and a single method named DoIt which accepted a string as a parameter.
In the DoIt method, I added a call to MyStaticClass.Call, passing the string parameter.

3. Demo
Back in Demo, I wrote the following in the program Main:
---
Assembly TheAssembly;
Type TheType;

MyStaticClass.Call("main start");

TheAssembly = Assembly.LoadFile("**PATH**");
TheType = TheAssembly.GetType("ReflectedClass");

if (TheType != null)
TheType.GetMethod("DoIt").Invoke(Activator.CreateInstance(TheType), new object[] { "hello" });

MyStaticClass.Call("main end");

---

I added a breakpoint to the static constructor in MyStaticClass, but was disappointed to see it only get hit once. It seems I had not managed to reproduce the scenario that my colleague had experienced.

I spent some time trying to figure out precisely what would cause the static class to be constructed mulitple times.
In the end I discovered that it could be achieved in the following way:
1. In the program code, making a copy of the ReflectedAssembly and Demo Assemblies in a different folder.
2. Using Assembly.LoadFrom to load the ReflectedAssembly Assembly as opposed to Assembly.LoadFile.

Once my code was changed to use this method, I found that my static constructor was being invoked twice.

Next, I wanted to find out why this was happening.
I added some additional code to the Call method in MyStaticClass, such that the following information was also written out to the Console:
  • The process ID

  • The managed thread ID

  • The AppDomain ID

  • The handle of the current Call method

I was hoping to see that somewhere, one of these values would be different.
My initial concern was that there may be some kind of context based issue around multi-threading.

After running the program again, I discovered that the process, thread and AppDomain IDs were all the same.
The difference was in the MethodHandle for the Call method.
In the two calls from the program Main (where "main start" and "main end" were written), the handle is the same, but in the call from ReflectedClass, the handle was different.
This seems to indicate that the instance of MyStaticClass that is used by ReflectedClass differs from the instance used by the program Main, which would explain why the static constructor was being called twice.

By enumerating the Assemblies of the current AppDomain, I can see that there are actualy two copies of my Demo Assembly in memory.
It appears that each contains an instance of the static class MyStaticClass, and this is why the static constructor has been invoked twice.
It is interesting to note that if I use Assembly.LoadFile to load ReflectedAssembly, there will also be two copies of the Assembly in memory, but the reference to the Assembly has been resolved to the same instance as my program Main is running.
However, if I use Assembly.LoadFrom, there seems to be an issue with resolving the reference to the existing Assembly and the reference is resolved to the new Assembly in memory instead.

I decided to take my work a little further and see if I could produce multiple instances of the static class in memory.
I modified my program so that it loads the ReflectedAssembly Assembly three times, from a different location each time.
If I use Assembly.LoadFile, although the Assembly is actually loaded into memory an additional three times, the reference to Demo is always resolved to the first copy in memory, the static constructor only runs once, and the calls to the MyStaticClass.Call method are on the same instance of the static class.
However, using Assembly.LoadFrom (with the Assemblies in a different location each time) causes the same behaviour as before - this time the static constructor is invoked 4 times, and the calls to MyStaticClass.Call are on different instances of the static class.

I refer to the MSDN entry for the Assembly.LoadFrom method:
"If an assembly with the same identity is already loaded, LoadFrom returns the loaded assembly even if a different path was specified."
This does not appear to be true. The code I ran above demonstrates that actually, LoadFrom is returning the newly loaded Assembly each time, and that the Assembly references are being resolved to newly loaded Assemblies too.

Demo Program
A demo program that shows this in detail can be downloaded here.
You are welcome to the source code, which is written in C# 2.0. Please contact me if you would like it.

Conclusion
Static classes and static constructors may only static in the context of the loaded Assembly.
If using Reflection to load Assemblies, you may unknowingly end up with multiple instances of your static classes contrary to accepted wisdom.
Essentially, you cannot rely on there being a single instance of a static class in your AppDomain.

In addition, using Assembly.LoadFrom does not guarantee that any Assemblies you are loading are resolved to in-memory copies, despite what is asserted in MSDN.
This is particularly important because this is what it appears is happening when using WCF in .Net 3.0.

None of this necessarily poses a problem however: as long as we are aware that this is the case we can work with it.

Sunday, 2 December 2007

Private Invoking Using Reflection

Whilst working on a product the other day, a thought occured to me with regard to Reflection in Microsoft.Net.
I wondered whether it would be possible to create an instance of a type with Internal or Private scope which was located in another assembly.

As I understand it:
  • An object declared with Internal scope should only be visible inside the assembly in which it is located.

  • An object with Private scope should only be visible to the object that contains it. Private objects can not be declared at namespace level, only within other objects.
To see whether it was possible, I created a test.
I created a Class Library, FormLib, which contained a Public class name FormWrapper.
FormWrapper contains three further classes: PublicForm, InternalForm and PrivateForm.

PublicForm is declared as a Public class with a Public constructor.
InternalForm is declared as an Internal class with an Internal constructor.
PrivateForm is declared as a Private class with a Private constructor.
All three classes inherit from Form and contain a single Label control that states "This is a ... form", with "..." replaced by the scope of the class.

I then created a Windows Forms project called Demo which contained a Form. Demo is the startup project.
In Demo, I added three buttons, which would attempt to create an instance of PublicForm, InternalForm and PrivateForm respecitvely.

To start, I needed to obtain the Assembly object representing FormLib. This was relatively easy and was achieved by referencing FormLib from my Demo project and then enumerating the Assembly objects contained in the current AppDomain:
---
...
Assembly _Target;

foreach (Assembly Item in AppDomain.CurrentDomain.GetAssemblies())
{
  if (Item.FullName.StartsWith("FormLib"))
  {
    _Target = Item;
    break;
  }
}
...

---

I assumed creating an instance of the Public class would be easiest, so I implemented this first.
The Assembly object has a method CreateInstance, which can be used to generate an instance of a type, as so:
---
...
object TheObject;

TheObject = _Target.CreateInstance("FormLib.FormWrapper+PublicForm", false, BindingFlags.Public | BindingFlags.Instance, null, null, null, null);
...

---

The first parameter of CreateInstance is the full name of the type I want to create.
"FormWrapper+PublicForm" indicates that the type PublicForm is inside the type FormWrapper, which is unlike the standard syntax for a type inside a namespace, which would simply be "Namespace.Type".
The third paremeter, which is a BindingFlags enumeration, indicates:
  • Public - The public declarations of the type should be searched

  • Instance - An instance should be created
The way that CreateInstance actually works is to generate the Type specified in the first parameter ("FormLib.FormWrapper+PublicForm" in this case) and then using the static CreateInstance method of the Activator object to actually generate the instance. This in turn uses RuntimeType.CreateInstanceImpl (RuntimeType is Internal to System) which actually invokes the constructor of the Type.
We could, of course, use Activator directly, but we would be unable to do this with Internal and Private types in a different Assembly because the types are not available to us directly.

Now if the above code works, I want to actually display the form I have just created. To achieve this, following the above code I carry out the following:
---
...
if (TheObject is Form)
{
  Form TheForm;

  TheForm = (Form)TheObject;
  TheForm.ShowDialog();
}
...

---

I ran my code to see what happened, and PublicForm was shown as expected.

Moving on, I decided to try and repeat the above with the Internal and Private classes.
To achieve this, I made a small modification to the call to CreateInstance, first to create the types of the InternalForm and PrivateForm types, and second to change the BindingFlags to Private instead of Public:
---
...
TheObject = _Target.CreateInstance("FormLib.FormWrapper+InternalForm", false, BindingFlags.Private | BindingFlags.Instance, null, null, null, null);
...
TheObject = _Target.CreateInstance("FormLib.FormWrapper+PrivateForm", false, BindingFlags.Private | BindingFlags.Instance, null, null, null, null);
...

---

Upon executing the code, in both cases the form was shown as expected.
To provide further proof that internal or private methods could be executed using reflection, I decided to add a method named "AMethod" to each of the classes.
The scope of the method was the same as the class itself, so there was a Public, Internal and Private method.
In each method, a messagebox will be shown displaying that the method had been invoked.

Directly following the line "TheForm.ShowDialog();" in each case I added the following code to attempt to invoke the method:
---
...
foreach (MethodBase Item in TheObject.GetType().GetMethods(BindingFlags.Public | BindingFlags.Private | BindingFlags.Instance)
{
  Item.Invoke(TheObject, null);
  break;
}
...

---

The objective of the above code is to enumerate all of the publically and privately available methods in the type represented by TheObject.
This reveals the "AMethod" method (which is of type MethodBase), which I can then invoke by calling Invoke and passing the instance of the type in as a parameter.
The second parameter for Invoke is the parameters for the method call (which can be passed as an array of objects - "object[]"). In this case, the method has no parameters so I simply pass in null.

The method could also be invoked by using the InvokeMember method of the Type. However, I found this unsuccessful with methods with Private access so I discounted it.

A Potential Solution
A method that you could use to add some protection to your internal or private code is to monitor the stack trace when your method is invoked. You could also do this upon object construction by adding a monitor to your class constructors.
Basically, you can retrieve a list of the current call stack at the start of each method and ensure that the call to your method came from within your own class or within your own assembly, depending on whether it is a private or internal method respectively.
The following code demonstrates the use of this to ensure the caller is in the current assembly, which will validate access to an internal method:
---
...
StackTrace Trace = new StackTrace();
if (Trace.FrameCount > 2)
  if (Trace.GetFrame(1).GetType().Assembly != Assembly.GetExecutingAssembly())
    throw new Exception("The call to this method is invalid");
...

---

This works by examining the second method on the call stack (frame 1), which will be the direct caller of the current method on the call stack (frame 0). If the caller is not in the same assembly as the current frame then you know that it is in another assembly and has not been made internally.

This works a treat but sadly adds complexity to your program and slows it down. However, if you are producing code that must only be executed internally or privately, this method may offer a reasonable way of protecting it.

Conclusion
You may create classes for internal use only in your assembly, which have internal or private members, properties or methods, but you cannot rely on the fact that these classes and members will not be created and consumed outside of your own code.
The power of .Net Reflection demands that you must not consider your internal and private code to be internal or private.

If you would like the demo program I produced to show this working, it is available here.

Until next time!

Sunday, 18 November 2007

Comparing ISINST to CASTCLASS

I was reading through a corporate C# coding standard the other day for one of my clients, and noticed that one of the coding requirements in the standard related to casting of types in code.
Their standard stated that all type conversions in C# should be accomplished by using the 'as' keyword rather than using a direct cast (i.e. '(type)').
I quizzed my client on this to see what formed the basis of their choice to use 'as'. They had no explanation, but said that they felt it could be faster.

Following on from this, I was interested to see whether using 'as' or '(type)' was faster for type conversion.

In .Net IL, 'as' is compiled to 'isinst'. isinst performs a type conversion and returns null if the specified type conversion is not valid.
This differs from using '(type)', which compiles to 'castclass'. castclass also performs a type conversion but throws an Exception if the specified type conversion is not valid.
This is an important difference. For example, consider the following example using 'as' (isinst):
void Foo1(object ObjA)
{
  ClassDef ObjB;

  ObjB = ObjA as ClassDef;
  ObjB.Property = "12345";
}


In the example, we have to be certain that we know ObjA can be converted to the ClassDef type, ObjB, because if it cannot, a NullReferenceException will occur in the line where the property is set.
A better implementation of the above example could be:
void Foo2(object ObjA)
{
  ClassDef ObjB;

  ObjB = ObjA as ClassDef;
  if (ObjB != null)
    ObjB.Property = "12345";
}


If we consider the same example using '(type)' (castclass):
void Foo3(object ObjA)
{
  ClassDef ObjB;

  ObjB = (ClassDef)ObjA;
  ObjB.Property = "12345";
}


Again in this example we have to be sure that the conversion between the two types is valid, because else a TypeConversionException will occur on the line where ObjA is cast to ClassDef.
There could be two potential alternatives to the castclass example:
void Foo4(object ObjA)
{
  try
  {
    ClassDef ObjB;

    ObjB = (ClassDef)ObjA;
    ObjB.Property = "12345";
  }
  catch (Exception ex)
  {
    // Do something useful
    throw ex;
  }
}

void Foo5(object ObjA)
{
  ClassDef ObjB;

  if (ObjA is ClassDef)
  {
    ObjB = (ClassDef)ObjA;
    ObjB.Property = "12345";
  }
}


In the examples above, Foo1 and Foo3 would be appropriate to use if we knew that the object ObjA can definitely be converted to ClassDef. However, this may not always be likely, particularly in these examples becuase the parameter ObjA is an object type.
In these circumstances, it could be more appropriate to use Foo2, Foo4 or Foo5, because they offer security against failures during the conversion process.
In Foo2, we rely on isinst returning null if the conversion is not valid, and so we check for null after the conversion.
In Foo4, we handle an exception that could be raised during a failed castclass.
In Foo5, we first check to see whether ObjA is a ClassDef (using isinst - 'ObjA is ClassDef') and then perform the conversion in the knowledge that it will not cause an exception.

Now I had five potential examples for performing a type convesion, I thought it would be interesting to see whether there was a great deal of difference in the time taken to carry out the different examples.
I wrote a test project which used a high-precision StopWatch to time each of the procedures.
I timed each procedure as it performed one billion casts, repeated over 50 iterations to ensure that a good average time could be ascertained.
Following on from this I analysed the results to see which of the above five examples was fastest.

The total time for all 50 billion conversions for each test were:
Foo1 = 1,466,176 ms
Foo2 = 1,506,633 ms
Foo3 = 1,499,661 ms
Foo4 = 1,519,072 ms
Foo5 = 1,689,141 ms

And the average times per iteration (1 billion conversions) were:
Foo1 = 29,323.52 ms
Foo2 = 30,132.66 ms
Foo3 = 29,993.22 ms
Foo4 = 30,381.44 ms
Foo5 = 33,782.82 ms

Foo1 was the fastest, closely followed by Foo3 (which was around 2.284% slower).
However, as neither Foo1 or Foo3 contain any checks to ensure that the conversion was a success so they may be unsuitable for general use.

Of the remaining methods, Foo2 was fastest, which involved checking for a null value after using isinst, followed by Foo4 (the the try...catch block around castclass) and finally Foo5, which was a combination of isinst and castclass. Foo5 was significantly slower than all the other methods, being around 3.5 seconds\million conversions slower than the slowest of the other four methods.
In order to directly compare isinst and castclass, we can examine Foo1 and Foo3. Consider the IL for Foo1 and Foo3 respectively:
Foo1
...
IL_0014  ldloc.2
IL_0015  isinst    TestCastStyle.ClassDef
IL_001a  stloc.1
IL_001b  ldloc.1
IL_001c  ldstr     "12345"
IL_0021  callvirt  instance void TestCastStyle.ClassDef::set_Property(string)
...


Foo3
...
IL_0014  ldloc.2
IL_0015  castclass TestCastStyle.ClassDef
IL_001a  stloc.1
IL_001b  ldloc.1
IL_001c  ldstr     "12345"
IL_0021  callvirt  instance void TestCastStyle.ClassDef::set_Property(string)
...


The code for the methods is identical, other than IL_0015, which uses isinst in Foo1 and castclass in Foo3.

In the tests I ran, Foo1 took around 29.32ms\million conversions whereas Foo3 took 29.99ms\million, which is a difference of 0.67ms\million.
This confirms that using isinst is definitely quicker than castclass.

Considering the scenario where a check must be performed to ensure the conversion is valid, we can compare Foo2 (isinst) to Foo4 or Foo5 (castclass). The IL for these methods is:
Foo2
...
IL_0014  ldloc.2
IL_0015  isinst    TestCastStyle.ClassDef
IL_001a  stloc.1
IL_001b  ldloc.1
IL_001c  brfalse.s IL_0029
IL_001e  ldloc.1
IL_001f  ldstr     "12345"
IL_0024  callvirt  instance void TestCastStyle.ClassDef::set_Property(string)
...


Foo4
...
try
{
  IL_0014  ldloc.2
  IL_0015  castclass TestCastStyle.ClassDef
  IL_001a  stloc.1
  IL_001b  ldloc.1
  IL_001c  ldstr     "12345"
  IL_0021  callvirt  instance void TestCastStyle.ClassDef::set_Property(string)
  IL_0026  leave.s   IL_002b
}
catch [mscorlib]System.Exception
{
  IL_0028  pop
  IL_0029  rethrow
}
...


Foo5
...
IL_0014  ldloc.2
IL_0015  isinst    TestCastStyle.ClassDef
IL_001a  brfalse.s IL_002e
IL_001c  ldloc.2
IL_001d  castclass TestCastStyle.ClassDef
IL_0022  stloc.1
IL_0023  ldloc.1
IL_0024  ldstr     "12345"
IL_0029  callvirt  instance void TestCastStyle.ClassDef::set_Property(string)
...


At first glance, I had assumed that Foo4 would be slowest of these methods, but the results were:
  • Foo2 took 30.13ms\million conversions

  • Foo4 took 30.38ms\million conversions

  • Foo5 took 33.78ms\million conversions


I was surprised to see that Foo5 was by far the slowest. There does not seem to be a massive difference between Foo2 and Foo4 under the test conditions, but if an Exception was raised at IL_0015 in Foo4, this would slow the method down considerably, whereas Foo2 would continue to be very quick.

The conclusions from the tests I performed are:
  • In a direct comparison, isinst is quicker than castclass (although on slightly)

  • When having to perform checks to ensure the conversion was successful, isinst was significantly quicker than castclass

  • A combination of isinst and castclass should not be used as this was far slower than the quickest "safe" conversion (over 12% slower)


If you would like to run the tests yourself, drop me an e-mail and I will send you the test program I used. Additionally, if you would like the analysis files containing the timings and code dumps, I can also send you this.

Have fun!

Friday, 2 November 2007

Using Win32 to Manipulate the UI

Whilst working on an application at a client's site the other day, I noticed that access to certain code was being controlled by disabling buttons on a form.
The code in question should not be invoked under certain conditions (in this case, under certain security conditions), and so the application developers had assumed that disabling the button that invoked the code would prevent the user from invoking the functionality behind the button.

Sadly, this is not the case.
I demonstrated a very simple attack using Win32 API calls that enabled the button, and allowed the user to click on it, whether or not the application had disabled it or not.

In this article, I will be discussing the technique I used, and how you can write code that is protected from this kind of attack.

To demonstrate the attack to my client, I implemented my code in Microsoft Excel. I did this because most desktop PCs tend to have Microsoft Excel and I wanted to show my client that you do not need development tools like Visual Studio in order to orchestrate a simple attack like this.
In addition, I used a standard network user account to to show that this attack can be performed by a standard user, with the only requirement (in this scenario) being access to VBA in an Office product and the ability to execute macros in the product.

In order to enable the disabled button, the user will need to carry out the following actions:
- Find the window handle (HWND) of the button
- Enable the button

To start new Microsoft Excel workbook should be created, and the Visual Basic Editor (Tools -> Macros -> Visual Basic Editor) should be open.
A new Module must be added to the current workbook. The following code must go into the Module - it will not work unless it is in a VBA code Module (not WorkSheet or WorkBook code).

Find the HWND
In order to enable the button, the user needs to know the window handle (which is often referred to as the HWND) of the button.
If the user can use a tool such as Spy++ this is very easy, but as most users will not have it we need a way of discovering the window handle from Excel.

An easy way to do this is to produce a list of window handles that exist in the current session.
This is done by making an API call to EnumWindows (which lives in user32).
EnumWindows requires a callback to enumerate the window list, which is simple to achieve in Excel; We simply declare a method that matches the callback specification:
---
Private Function EnumWindowsProc(ByVal hwnd As Long, ByVal lparam As Long) As Long
---

This method matches the requirement, so we can now make the API call as required. To do this, we need to make the API method declaration and call it:
---
' This is the API method declaration
Private Declare Function EnumWindows Lib "user32" (ByVal callback As Long, ByVal lparam As Long) As Boolean

' This method, when invoked, will make the API call
Public Sub EnumerateAllWindows()
  EnumWindows AddressOf EnumWindowsProc, 0
End Sub
---

When the EnumerateAllWindows method is invoked, the API call is made to EnumWindows, and our callback method (EnumWindowsProc) will be invoked.

In EnumWindowsProc, we get passed a window handle in hwnd. The lparam parameter serves no purpose in this example and can be ignored (it will be 0).
The value in hwnd will be the first enumerated window handle. To get the next one, the EnumWindowsProc must return a true value:
---
Private Function EnumWindowsProc(ByVal hwnd As Long, ByVal lparam As Long) As Long
  Debug.Print hwnd
  EnumWindowsProc = 1
End Function
---

This will then be repeatedly invoked until all the window have been enumerated, and the Immediate window will now contain a list of a couple of hundred numbers.

However, this is not very useful as far as the user is concerned, because they do not know which of these window handles are any use to them.
To help the user, the name of the window whose handle has been displayed can also be obtained.
To do this, an API call to GetWindowTextA (which also lives in user32) can be made, which has the following API method declaration:
---
Private Declare Function GetWindowTextA Lib "user32" (ByVal hwnd As Long, ByVal Text As String, ByVal maxcount As Long) As Long
---

And now in EnumWindowsProc, the following code is added before the Debug.Print statement:
---
  Dim Length As Long
  Dim Text As String

  ' Empty string to accept a name
  Text = String(100, " ")

  ' Get the text
  Length = GetWindowTextA(hwnd, Text, 100)
  If Length > 0 Then
    Text = Mid$(Text, 1, Length)
  Else
    Text = ""
  End If

  Debug.Print Text
---

There are some important points to note when using GetWindowTextA:
- A string (named Text) of length 100, containing spaces, was created for the string to be put into. This must be done, else the string will always be empty.
- The resulting string (from GetWindowTextA) was terminated using the length returned. If this was not done the Text would contain a string terminator (null, '\0') and then spaces up to the 100th character and would be unusable.

After including the above code, invoking the method will dump the name of the window and the window handle to the immediate window.

As event this output is not ideal, Excel can be used to dump the list to the current Sheet. A member variable, RowCounter, of type Integer is added to the Module, and then in EnumerateChildWindows method, is set this value to 1.
Now in EnumWindowsProc, the Debug.Print statements are changed to:
---
  Application.ActiveSheet.Cells(RowCounter, 1).Value = Str(hwnd)
  Application.ActiveSheet.Cells(RowCounter, 2).Value = Text

  RowCounter = RowCounter + 1
---

When this code is now invoked, it dumps a list of window handles and window names to the current spreadsheet - much more useful when looking for something.

Now that is done, a list of the window handles in the system can be obtained. This can be tested by running Calc (calc.exe) and then invoking EnumerateAllWindows. The text "Calculator" will be visible next to a window handle on the list somewhere.

That's a good start, but if the user is trying to enable a button on a form, at the moment they will only have visiblity of the form's window handle.

To have a look at what is on the form, another API call, EnumChildWindows. EnumChildWindows will be used to enumerate all the child windows of a specified window handle.
Each button (and indeed most forms components) will have their own window handle.
The declaration for EnumChildWindows is:
---
Private Declare Function EnumChildWindows Lib "user32" (ByVal hwndParent As Long, ByVal callback As Long, ByVal lparam As Long) As Boolean
---

In the declaration hwndParent refers to the parent window handle, and then the callback and lparam parameters are the same as before.
To use EnumChildWindows, another callback method is required, which is declared in the same was as with EnumWindowsProc:
---
Private Function EnumChildWindowsProc(ByVal hwnd As Long, ByVal lparam As Long) As Long
---

The method body is the same as EnumWindowsProc, so it will also produce a list of window handles and associated text.

A method called EnumerateChildWindows is declared, which will read the number (window handle) in the currently selected cell and enumerate child windows of it:
---
Public Sub EnumerateChildWindows()
  If IsNumeric(Application.Selection) Then
    Dim Number As Long

    Number = Application.Selection
    If Number > 0 Then
      Application.ActiveSheet.Cells.Clear
      RowCounter = 1
      EnumChildWindows Number, AddressOf EnumChildWindowsProc, 0
    End If
  End If
End Sub
---

If the user clicks on a window handle in the worksheet and then runs the method EnumerateChildWindows, the current list will be cleared and then the child windows of the selected window handle will be displayed.

This can be repeated if necessary to pass through multiple layers of child windows, but it is most likely that the button the user is looking for has been found the first time EnumerateChildWindows is invoked.

This can be tested this by:
- Run Calc (calc.exe)
- Invoking EnumerateAllWindows
- Selecting the window handle next to "Calculator" in the list
- Invoking EnumerateChildWindows
A list that contains all of the controls on the Calculator form should now be displayed.

The user will now be able to obtain the window handle of the button they wish to enable.


Enable The Button
In the above section, the user can obtained the window handle for a control that they wish to enable.

Now the user needs to enable the button.
This is achieved by making an API call to EnableWindow, which is declared in user32:
---
Private Declare Function EnableWindow Lib "user32" (ByVal hwnd As Long, ByVal state As Boolean) As Boolean
---

When making the API call, the window handle must be supplied in hwnd, and the enabled state of the target window in state.
A method can be declared to do this:
---
Public Sub EnableSelectedWindow()
  If IsNumeric(Application.Selection) Then
  Dim Number As Long

  Number = Application.Selection
  If Number > 0 Then
  EnableWindow Number, True
    End If
  End If
End Sub
---

Now, the user can simply select a window handle in the list in the spreadsheet and invoke EnableSelectedWindow, and the window will become enabled.

This can be tested by:
- Run Calc (calc.exe)
- Putting Calc into Scientific mode (View -> Scientific). Note that the Ave, Sum, s, Dat, A, B, C, D, E and F buttons are disabled
- Invoking EnumerateAllWindows
- Selecting the window handle next to "Calculator" in the list
- Invoking EnumerateChildWindows
- Select the window handle next to one of the disabled button names (i.e. "Ave") - Invoking EnableSelectedWindow

The button will now be enabled. This can repeated as many times as necessary with other controls on the form.

This method will work on anything that has a window handle in Win32.

Conclusion
It is very easy to modify the state of controls using Win32.
This is because almost all standard controls in Windows have a window handle. This is a fundamental part of the operation of Microsoft Windows, and cannot be prevented.

It is important when designing and developing UI-invoked code that preventative steps are always taken to double-check that code execution is permitted.
As this article has demonstrated, it cannot be assumed that code is protected by simply disabling or hiding UI components.
A much more secure method would be to disable a control but to verify that execution is permitted inside the control's Click event or inside the code that is being executed.

Additionally, it is important to realise that it is not only the Enabled state of controls that can be influenced. In fact, using the same principal described in this article a user can change any of the following aspects of a window:
- Colour
- Position
- Size
- Visibility

Following the demonstration of the above to my client, they readily agreed that a better approach to protecting code from unwanted execution was required, and they have taken steps to prevent code access in this way.

If you would like to download a copy of the code used in this article, it can be downloaded here. This code is written (as per this article) for use in Microsoft Excel but can easily be changed to work with other Office products.

Have fun!

Monday, 10 September 2007

Trial Game Unlocking

The other day, I downloaded a trial version of a game from a website.
The game was a fairly simple one where you have a series of balls rolling along a track, and you have to shoot coloured balls at them to cause them to pop.

I was enjoying the game a lot - it was great fun - but then after 60 minutes the game turned itself off and displayed a message stating that my trial was over and that I would have to purchase the game to continue playing.
A lot of software these days is based on trial use systems, whereby the user is entitled to a certain amount of use of the program, and then after a this time has been used the program locks itself so that it can no longer function, or functions with severely reduced functionality.

The problem with this method of software protection though, is that the actual program is still on the user's PC - after the trial period the software "locks" but is actually still fully available.

With this in mind, I decided to have some fun seeing how easy it would be to simply bypass the trial protection and to continue playing the game.
Before I continue, I would like to say that I do believe people should pay a fair price for software, as I myself am aware of how much effort goes into producing applications and games, and that I did actually purchased the software in question.

To start, I installed the software on a new PC, thereby unlocking it for full use.
I then ran the software.
The first thing that happened was that a nag screen appeared which informed me that I had only 60 minutes of free gameplay left. I clicked on the Play button on this screen to start the game. The nag screen then disappeared and a couple of seconds later the game appeared on screen.

I closed the program, and then opened OllyDBG. I opened the program in OllyDBG and selected Run. The nag screen appeared.
At this point I Paused OllyDBG and noticed I was in kernel32. I selected "Execute till user code".
I now noticed I was in a large proc that seemed to control the trial window that had been displayed.
As the trial window had been kind enough to inform me how much time was left in my trial period, I knew that this value had to have been supplied from somewhre, so I decided to have a look through the proc.
I saw something that interested me at +5FAD, which was the following:
  PUSH   00533940   UNICODE "gTimeLeft"
Now time left could of course be for a number of different things, but it was a good place to start looking for what I was after. I set a breakpoint on this line and then let the program continue to run.
However, my breakpoint did not hit. So I tried a different method, I restarted the program, and then checked to ensure the breakpoint was still set on that line.
I then seleced Run.
A short while later, the breakpoint was hit - this was obviously used as part of the initialisation of the trial screen rather than during it's general running.

The first thing I did now that the breakpoint had hit was to have a look at the new few lines of code:
+5FAD  PUSH   00533940                    UNICODE "gTimeLeft"
+5FB2  LEA    ECX, DWORD PTR SS:[EBP-2C]
+5FB5  CALL   +87D3
+5FBA  MOV    DWORD PTR SS:[EBP-4], 1D
+5FC1  PUSH   DWORD PTR DS:[5BA530]

I made the initial assumption that at +5FB5, there was a call to a proc that retrieved this value "gTimeLeft". I quickly stepped through the proc and resulting sub-proc calls to see whether I could find anything obvious, but couldn't.
I decided to get back to the main proc and step through this to see whether there was anything else helpful.
I stepped through until I got to +5FC1, where the value at 5BA530 was pushed onto the stack.
The value at this location turned out to be 0x3C (60), which was identical to the 60 minutes displayed on the trail screen. However, this could be pure coincidence and I wanted to be sure.
I set a new breakpoint on this line and then let the program run. I played it for a couple of minutes and then closed it.
After OllyDBG had informed me that the process had terminated, I restarted and ran the program, and shortly afterwards my breakpoint was hit again. This time the value was 0x3A (58). I let the program run so that the trial screen would appear, and lo and behold the message displayed the fact that I had 58 minutes remaining in my trial.

Armed with an apparent location for the amount of time left in the game, I restarted the program, and then decided to perform an analysis on any code which accessed this memory location (5BA530).
In OllyDBG, I examined the location in memory and then used "Find References" to enumerate all the places where this memory location was referenced.
It turned out that there were 4 locations:
+37B4  MOV    DWORD PTR DS:[5BA530], EAX
+5FC1  PUSH   DWORD PTR DS:[5BA530]
+6391  CMP    DWORD PTR DS:[5BA530], EBC
+68DC  PUSH   DWORD PTR DS:[5BA530]

The most sensible way to proceed was to set a breakpoint on each of them, which I then did, and I then restarted and ran the program again.

The first breakpoint that was hit was at +37B4, which seemed to load the number of remaining minutes into the memory location. At this stage, I thought that a simple modification of this line would allow one to play indefinitely, but I wanted a slightly cleaner solution, so I continued execution.
The next breakpoint hit was at +5FC1, which is where the value seemed to be loaded for display on the trial screen. I again continued execution. The trial screen was displayed, so I clicked on the Play button to load the game itself.
The next breakpoint to be hit was at +68DC. This was used to generate a debug message output using OutputDebugStringA in Kernel32. I removed this breakpoint (as it was hit every second) and again continued execution.
However, the final breakpoint was not hit, and so I decided to exit the game and see whether that may trigger anything, but it did not. The process terminated.

So now I had a single point at which I could manipulate the game, +37B4, where the initial remaining time had been set. I restarted the program and ran it until this breakpoint was hit again.
I could easily of changed the remaining time value at this point, or simply modify the code so that instead of loading the remaining time into the address, it always loaded a high fixed value, but this didn't seem like a particularly elegant solution, so I wanted to actually find out where the trial screen was displayed so I could see whether there was a better way of influencing the program.
I stepped through the code until the proc returned (at +37C6). I stepped through the code here, and noticed that at +61FD, there was a call to +61BD, and that if I stepped over this, the trial screen was displayed and the game seemed to load. This is where I put my next breakpoint.
I restarted and ran the program, and then stepped into the proc that was called. I saw that the called proc only had a single call, so I stepped into this too.
Now I ended up in the large proc that contained the "gTimeLeft" line I found earlier, and a reference to the remaining time in 5BA530 (at +5FC1).

I don't want to go through this large proc. A quick glance at it tells me that this is where the trial registration screen is displayed, and I want to intercept the execution before it gets here.
With this in mind, I go back to the original call into the large proc, and back to the original call into the calling proc, which is at +61FD.
There is a small proc here, which includes the line at +61E8:
+61E8 PUSH 00533970 ASCII "TrialScreen"
Now this is starting to look more interesting. This proc seems to be concerned with launching the trial screen. I would like to see where it is called from, so I examine the start of this proc, at +61D7 and see that there is a single call from +7FE3, which I go to.
I put a breakpoint on +7FE3, and then restart and run the program. The breakpoint hits straight away, so I decide to step over the line - I am not interested in how the trial screen is displayed at the moment - and see what happens.
As expected, the trial screen is displayed. I click the Play button and see that the trial screen closes, and immediately I am back into my code, at +7FE8. The line I just stepped over is just responsible for displaying the trial screen.
The line I am now on (at +7FE8) contains the a JMP to +81A6.
If I run the program now the game will load.
So, what will happen if I replace the CALL in +7FE8 with NOP instructions? Will the game load without a trial screen?
I decide to try it, and as I hoped, the trial screen is not displayed - the game just loads. I have managed to find where the trial screen is displayed from.

I decide to have a look around to see what is going on with the code - I am particularly interested in the events leading up to the display of the trial screen.
I notice that there is a CMP at +7FD8 and a JNZ at +8FE1 just above the call to the trial screen. I set a breakpoint on these to see what is happening in them.
After restarting the program, I notice that the CMP is checking to see whether a value is 0 or not. If the value is 0, a JMP is made to the next line at +7FED, essentially this skips the trial screen.
I decide to force this jump by altering the Z flag. I then allow the program to run to see what has happened.
I actually end up being presented with a screen that tells me my trial period is over, and I can no longer play the game. I assume, from this, that this must be what gets called when there are no minutes left to use up and you cannot trial the game any more.
This isn't what I'm looking for though, so I have a look further up the proc to see what I can find. I notice that there is another CMP just above, at +7FC9. I put a breakpoint on this line, and notice that it has jumps from +7E9B and +7EB7.
I want to know whether either of these jumps are what leads to this instruction or whether the execution simply continues from the previous instruction (+7FC7) so I set a breakpoint on +7FC7.
I restart and run the code and see that the instruction +7FC9 is jumped to, because the breakpoint at +7FC7 is never triggered.
There is a JBE just after the CMP. This is always taken. If I force it not to be taken, I am presented with a screen asking for my order number for registration purposes. Again, not really what I am looking for.
So I decide to go back a bit further, to examine the jumps that led us to +7FC9, so I set breakpoints at +7E9B and +8EB7. Both jumps are actually JE instructions.

I restart and run the program, and the breakpoint on +7E9B is triggered, but I notice the JE instruction at this address is not followed. I continue execution.
The breakpoint on +7EB7 is then triggered, and this time the JE is taken, so this is where the program execution branches to the whole registration screen\trial screen\end of trial screen area.

Moving back down to look at the registration, trial and end of trial screen section in the proc, between +7FC7 and +7FF2, I notice that after each screen has been displayed (via a CALL), a JMP is made to +81A6.
Now this seems to be when the program is actually executed, so I go and examine the code located there.
Interestingly, the first things I notice are a ASCII reference to the program file, and a UNICODE reference containing the wors "Unable to extract game executable.".
This must be where the game is actually loaded from!
Now if the game is registered, then the entire section about registration screens and trial screens should be skipped, so I have a look and see if +81A6 is jumped to from anywhere else.
I can see the three jumps from the registration, trial and end of trial screens at +7FD6, +7FE8 and +7FF2, but there are also two additional jumps from +802D and +8049.
Both of these are located in some code that is just below the whole registration screen area, which starts at +7FF7.
I see that there are two jumps to +7FF7, one from +7E4F and one from +7E5B.
I go and have a look at these. They are both conditional JNZ based on CMP statements.
I set breakpoints, restart and run the code.

The breakpoint at +7E4F is triggered (as expected; it is first). I quickly notice that neither this or the second JNZ are taken, and then the execution quickly proceeds to the registration screen.
I thought it may be prudent to force one of the JNZ, so I pick the first one at +7E4F and restart the program.
When the breakpoint is triggered, I simply change the Z register so the jump is taken, and run the program. None of the screens are displayed, and the game loads and plays successfully.

I have found where I can bypass the registration and trial screens.
Simply changing the JNZ to a JMP (and filling the leftover byte with a NOP) will cause the program to execute every time, regardless of minutes remaining (0 or more). The software protection is, effectively, disabled.

Just to see for myself, I wanted to modify the actual EXE file to see whether this change could easily be made permanent.
I open the EXE using UltraEdit and quickly see that the code is not encrypted. I modify the few bytes so that the JNZ is a JMP, and then save the file.
I can now run it every time without any prompting what-so-ever. I have even tried patching it after the trial period ran out (after 60 minutes was up) and it still works.

This kind of technique of software protection is poor. It actually took me longer to write this article than it did for me to break the protection in this game.
The method used for this game relies on the fact that a wrapper has been produced around the game itself, and this wrapper provides all the registration and trial functionality. The actual game has no concept of this what-so-ever.
Also, the wrapper itself is poorly produced. The fact that I can bypass all the protection with a change to a single line of code is staggering. It would be better to have put a check into several places in the code, and also embedded further, regular checks into the game itself.
However, a lot of developers do not understand how vulnerable their code can be, particularly when they write their code in a language such as C++ and then compile it to assembler.
The actual assembler output from their C++ code may be very different from what they originally wrote, and could be susceptable to easy attack using methods like the ones I have used today.

I am not going to produce a patch for this particular bit of software, because I am reluctant to give away the ability to bypass the software protection on what is actually a very good game. Like I said at the start of my article, I have actually purchased this game because I like it so much, and the only reason I have produced this article is because of my academic interest in the protection methods used in the real world.

If you have any queries about this article, please do not hesitate to get in touch.

Until next time...

Thursday, 6 September 2007

Good Password Generation?

Following on from my previous articles about password generation and the potential flaws in using password generation tools, I thought it might be useful to produce a tool that generates robust passwords based upon a generation code (such as an asset number).

I had the following objectives for the tool:
- Generate passwords that were random every time
- Generate a repeatable password based on a numeric seed using an algorithm that was not easy to break
I also wished for the generation to be configurable:
- Allow passwords between 1 and 15 characters
- Allow a character set to be specified
- For random passwords, allow a quantity of passwords to be specified
- For repeatable passwords, allow an asset number to be entered

RANDOM PASSWORD GENERATION
I started off by looking at producing passwords that were random every time. These would not be based on asset codes, but instead should generate passwords that appear truly random when compared to each other.

I decided to implement two types of random password generator, both based on Microsoft .Net random number generators.
The first was to be based on the simple subtractive random number generator which is implemented by the .Net class Random.
The second would be based on the cyptographic random number generator, RNGCryptServiceProvider (in System.Security.Cryptography).

To produce the passwords, the random number generator would be used to supply a byte array containing a sequence of character positions from the character set used to seed the passwords.

For simplicity, say I was using the character set 'ABCDE' and I wanted a 8 character password.
I request a sequence of 8 bytes from the random number generator, each with a value between 0 and 4, and receive the byte array '0, 3, 2, 4, 4, 2, 0, 1'.
I then use these positions to retrieve characters from the character set, as so:
0 = A, 3 = D, 2 = C, 4 = E, 4 = E, 2 = C, 0 = A, 1 = B
Which gives a password 'ADCEECAB'.

Passwords based on random number generators can be good because there should be no discernable pattern present in the generated sequence.

However, passwords generated in this way do result in some security problems:
- The passwords are not repeatable because they are not based on an asset number. This means they have to be stored somewhere for later retrieval, which may potentially represent a huge security risk.
- The passwords may not be truly random. Random number generators work from a predefined formula for which gives the appearance of randomness, however, they are not truly random (see below for more on this).

Before I move on, I would like to discusss the randomness of the passwords that can be generated using a random number generator.
A simple random number generator, such as the Random class in Microsoft.Net, is a pseudo-random number generator, that is, the numbers that are generated are not random at all, they are derived mathematically using a formula, and the numbers appear to be random.
The Random class (in .Net) uses a "seed" to generate a sequence of numbers. In .Net, by default this is based on the number of ticks so far in the day. However, a seed can also be supplied directly to the class Constructor.
This highlights an important limitation of simple random number generators - if the same seed is used again, the sequence of numbers generated will be the same.

Create a simple program that instantiates a Random class with a seed of 1, and then gets the first 10 integers (Random.Next()).
Execute the program a few times. Each time the numbers generated will be the same, in the same order.
It is very important to accept that if the seed used to create the Random class can be ascertained, the entire sequence of numbers used to generate a password can be recreated, and this may prove the undoing of any password generator based on pseudo-random number generation.

REPEATABLE PASSWORD GENERATION
For a repeatable password to be generated, an asset code will be required. To simplify matters, the asset code will be limited to numerics only.

I decided to implement two repeatable password generators:
- Simple. This will be based on the principals outlined above with regards to using a fixed seed for random number generation. The seed will be the asset code.
- Complex. This will be based on a method that uses a predefined formula to generate the asset code. I will not reveal the formula because I would like to see whether anyone can figure it out for themselves.

To generate the actual passwords, the repeatable password generation will work in the same way as the random number generator, that is a sequence of valid numbers will be generated that will indicate the positions of the character to be used in the password from a character set.

Repeatable password generators offer advantages over randomly generated passwords, because they do not need to be written down anywhere; They can be generated at any later time simply by supplying the asset code.

However, they do have limitations:
- The password that is generated is, ultimately, based on a formula of some sort and so can be broken given a large enough set to work with
- The tool must be properly protected from unauthorised access. Access to the tool is, essentially, access to the entire system.

THE IMPLEMENTATION
I decided to implement each of the different generation methods (both random and repeatable) in classes that support a common interface, IRNG. This way my generation program does not care which actual implementation is being used to generate the passwords.

I wrote a manager class called PwManager, which will be responsible for generating the passwords using the desired generator.

I then placed the manager class, the interface and the generator classes in an assembly, and referenced this from my Windows Forms project.

In my Windows Forms project, I added a form to allow the user to configure the generation method, password length and character set and also, depending upon the chosen generation method, the number of passwords to be generated or the asset code.
I then added a second form which would be used to display the results of the generation.

When a button is pushed on the first form, the PwManager is instantiated and configured with the appropriate parameters, and the generation of the password(s) takes place. The resulting configuration information and password list is displayed on the second form.

DEMO PROGRAM
If you would like to download and use the password generator program, it can be downloaded here.

There are two assemblies in the download, a library and an executable. The executable is simply a UI which presents the functionality from the library.
Feel free to reference the library from your own code and make use of the generation methods.

A final note: Please do not use the program to generate passwords for your organisation - it is freely available on the web (from my blog) and others could easily obtain it. Instead, the source code is (as always) available upon request - ask me for it and modify it to make it unique to your organisation.

CONCLUSION
I have demonstrated several techniques for generating passwords during this article.
I would be interested to hear if anyone can break the repeatable password generators, you are welcome to try!

Monday, 3 September 2007

Bulk Password Generation Part 2

In my previous article I managed to demonstrate that a password generation technique implemented by a tool in an organisation could be easily broken with as few as 300 passwords.
In the article I broke the password generator for the BIOS passwords generated by the aforementioned tool.
In this article, I will discuss breaking the local administrator passwords generated by the tool, and then go on to discuss the tool required to reproduce the passwords.

It should be noted, before I continue, that I do not have the tool used to generate the passwords. Instead, I have been given a list of sequential passwords generated from the tool.
The tool itself generates passwords based on the asset tag of the PC they are for. The asset tags are a number.
The passwords I have been given are for the 500 assets numbered 0 - 499.

Referring to my previous article, the local administrator passwords are 8 characters long, and were structured like this:
UlUlUnns
Where U is Uppercase letter, l is lowercase letter, n is number and s was a symbol.

In the same way as before, I started by looking at the first few passwords:
0 JcVvI32(
1 KdWwJ43)
2 LeXxK54*
3 MfYyL65+
4 NgZzM06-
5 OhAaN17!

At this stage I began to get the same sinking feeling that I got when I worked on the BIOS passwords. The passwords are, again, sequential.
I briefly hoped that the producer of the password generator tool had the aptitude to at least use a different technique for the two different password types...
But fairly soon it became obvious that these passwords were as simple to break as the other ones.
In fact, using the same technique as demonstrated in my previous article, I broke the entire set of formulae for each letter in less than 20 minutes!
Although characters 2 and 4 of this password are lowercase, they are not mixed, so they are still as limited as the uppercase characters, i.e. 26 possibilities in the sequence.
The final formulae for each character turn out to be:
1) l = (n + 113) mod 137 mod 26
2) l = (n + 54) mod 153 mod 26
3) l = (n + 21) mod 113 mod 26
4) l = (n + 99) mod 117 mod 26
5) l = (n + 86) mod 193 mod 26
6) l = (n + 123) mod 127 mod 10
7) l = (n + 202) mod 239 mod 10
8) l = (n + 105) mod 129 mod 10

Where l is the final number of the character in the sequence, and n is the asset number.
The character sequence for positions 1, 3 and 5 is A - Z (0 - 25).
The character sequence for positions 2 and 4 is a - z (0 - 25).
The character sequence for positions 6 and 7 is 0 - 9 (0 - 9).
The character sequence for position 8 is '!#$%&()*+-' ('0123456789').

The only minor benefit that was present with these passwords is that a much larger sequence was needed in order to be sure of the generation techniques.
In fact, I needed the full 500 for character 7 and just under 400 for 3 of the others.

That said though, the generation technique is still extremely poor, for the same reasons that the BIOS password generator was poor, and also:

AS EASY TO BRUTE FORCE (Following on from previous article section)
The BIOS passwords could be relatively easily brute forced.
These passwords are as easy, despite the inclusion of the lowercase characters.
This is because, like the BIOS passwords, the entire sequence is strict in it's structure.
The lowercase characters are always at positions 2 and 4.
If, like with the BIOS passwords, the full character sequence could be used in each position (A-Z, a-z, 0-9, symbols) then there would be 72 possibilities at each position:
72^8 = 722,204,136,308,736
A whopping 722 trillion, over 60,784 times more than for the standard password, and still 36 times more than the strongest possible BIOS password (with 46 possibilities per position).


I had been asked if I could produce a tool that would reproduce the passwords, given the asset number.
I was now armed with the knowledge to do this, so I proceeded to produce a tool to do the work outlined in this and my previous article.

I decided to write the tool in C# (Microsoft.Net 2.0).
A screenshot of the tool is shown below:


To use the tool, enter the asset code into the 'Asset Code' textbox, and click the Go button.
The Administrator password will appear in the "Admin Password" box and the BIOS password will appear in the "BIOS Password" box.
The tool itself simply implements the formulae described in this and my previous article to generate the passwords.
If you would like the source code for the tool, please e-mail me and I will send it to you.

The tool can be downloaded here.


To conclude:
Using password generation tools is a good idea. Company administrators find such tools invaluable in producing random passwords for hundreds, or thousands, of computers at an organisation.
Generation tools can produce passwords that appear to be significantly more random than those that could be thought up by a human.
However, if poorly implemented, password generation tools can pose a significant security risk.
Consider some important facts:
- My friend was able to obtain a list of 500 passwords generated for sequential asset numbers without having any administrative access to his domain
- The password algorithm used was easy to break, being based on a sequential generation system
- The password implementation was extremely poor, using a fixed format and poor combinations of character sequences

The organisation in question would have had a significantly more secure system if:
- The tool was protected so that only administrators could access it
- The algorithms used were truly random
- The passwords were never sequential
- The password format was not predefined

I may explore a password generator program in my next article, to see how it could be done in a more secure way.

If you have any queries about this article then don't hesitate to contact me.

Have fun!