The following C# solution shows how to create an application that detects modifications through the use of the RIPEMD-160 cryptographic hash function. PatchDigest (configured to run as a post-build event of Calculator) searches Calculator.exe for the _embeddedDigest value, zeroes it, hashes the result, then overwrites the array with the actual digest. When Calculator is run it reads itself, zeroes _embeddedDigest, then hashes the result just as PatchDigest does before comparing the computed digest to the embedded one. If they don't match it is assumed the application has been modified in a malicious manner and, in an attempt to throw the attacker off, the output of the application is corrupted. This behavior can be observed by removing Calculator's post-build event and recompiling.
Download
Calculator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using System.Security.Cryptography;
namespace Calculator
{
class Program
{
private static byte[] _embeddedDigest = new byte[20]
{
0x00, 0x0F, 0xF0, 0xFF,
0x00, 0x0F, 0xF0, 0xFF,
0x00, 0x0F, 0xF0, 0xFF,
0x00, 0x0F, 0xF0, 0xFF,
0x00, 0x0F, 0xF0, 0xFF,
};
private static Random _rnd = new Random();
static bool CheckIntegrity()
{
string asmLocation = Assembly.GetExecutingAssembly().Location;
byte[] buffer = File.ReadAllBytes(asmLocation);
bool match;
for (int x = 0; x < buffer.Length; x++)
{
match = true;
for (int y = 0; y < _embeddedDigest.Length; y++)
{
if (_embeddedDigest[y] != buffer[x + y])
{
match = false;
break;
}
}
if (match)
{
for (int y = 0; y < _embeddedDigest.Length; y++)
buffer[x + y] = 0;
break;
}
}
RIPEMD160Managed ripemd = new RIPEMD160Managed();
byte[] digest = ripemd.ComputeHash(buffer);
match = true;
for (int x = 0; x < digest.Length; x++)
{
if (_embeddedDigest[x] != digest[x])
{
match = false;
break;
}
}
return match;
}
static void Main(string[] args)
{
Console.Write("X: ");
int x = int.Parse(Console.ReadLine());
Console.Write("Y: ");
int y = int.Parse(Console.ReadLine());
// if the integrity check fails replace y with a random value
y = CheckIntegrity() ? y : _rnd.Next();
Console.WriteLine("X + Y = {0}\r\n" +
"Press any key to continue...", x + y);
Console.ReadKey();
}
}
}
PatchDigest
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using System.Security.Cryptography;
namespace PatchDigest
{
/// <summary>
/// Usage: PatchDigest [Target Application]
/// </summary>
class Program
{
private static byte[] _embeddedDigest = new byte[20]
{
0x00, 0x0F, 0xF0, 0xFF,
0x00, 0x0F, 0xF0, 0xFF,
0x00, 0x0F, 0xF0, 0xFF,
0x00, 0x0F, 0xF0, 0xFF,
0x00, 0x0F, 0xF0, 0xFF,
};
static void Main(string[] args)
{
string file = args[0];
byte[] buffer = File.ReadAllBytes(file);
int index = -1;
bool patched = false;
for (int x = 0; x < buffer.Length; x++)
{
bool match = true;
for (int y = 0; y < _embeddedDigest.Length; y++)
{
if (_embeddedDigest[y] != buffer[x + y])
{
match = false;
break;
}
}
if (match)
{
index = x;
for (int y = 0; y < _embeddedDigest.Length; y++)
buffer[x + y] = 0;
RIPEMD160Managed ripemd = new RIPEMD160Managed();
byte[] digest = ripemd.ComputeHash(buffer);
for (int y = 0; y < _embeddedDigest.Length; y++)
buffer[x + y] = digest[y];
File.WriteAllBytes(file, buffer);
patched = true;
break;
}
}
Console.WriteLine((patched ? "Patched" : "Patch Failed") +
"Press any key to continue...");
}
}
}
No comments:
Post a Comment