۱۳۸۹/۰۷/۰۶

چگونه تشخيص دهيم اسمبلي دات نت ما وصله شده است؟


يكي از روش‌هايي كه براي بررسي يكپارچگي فايل‌ها مورد استفاده قرار مي‌گيرد و عموما در دنياي سخت افزار و firmware هاي نوشته شده براي آن‌ها مرسوم است، قرار دادن CRC32 فايل در قسمتي از فايل و بررسي آن حين Boot سيستم است. اگر CRC32 جديد با CRC32 اصلي يكسان نباشد به اين معنا است كه فايل در حال اجرا پيش تر دستكاري شده است.
اما در دات نت فريم ورك روش متداول اينكار چيست؟ براي اين منظور اضافه كردن امضاي ديجيتال به فايل و اسمبلي نهايي توليدي (فايل exe يا dll توليدي) توصيه مي‌شود (مراجعه به قسمت خواص پروژه و افزودن امضاي ديجيتال جديد فقط با چند كليك، +).
اين مورد خوب است (با توجه به اينكه از الگوريتم‌هاي RSA و SHA1 استفاده مي‌كند)، لازم است، اما كافي نيست زيرا ابزارهاي حذف آن وجود دارند. به عبارتي براي وصله كردن اين فايل‌ها فقط كافي است اين امضاي ديجيتال حذف شود و زماني هم كه نباشد، بررسي خاصي در مورد يكپارچگي فايل صورت نخواهد گرفت.
اما اگر باز هم نگران patch يا وصله شدن اسمبلي دات نت خود هستيد اين مورد افزودن امضاي ديجيتال را حتما انجام دهيد. مهم‌ترين خاصيت آن اين است كه يك سري تابع native در دات نت فريم ورك براي بررسي نبود آن وجود دارند (+):
[DllImport("mscoree.dll", CharSet=CharSet.Unicode)]
public static extern bool StrongNameSignatureVerificationEx(string wszFilePath, bool fForceVerification, ref bool pfWasVerified);

wszFilePath مسير فايلي است كه بايد بررسي شود.
fForceVerification آيا متغير pfWasVerified نيز مقدار دهي گردد؟
خروجي تابع مشخص مي‌سازد كه آيا strong name موجود و معتبر است يا خير؟

و مثالي از استفاده‌ي آن (كه بهتر است در يك تايمر نيم ساعت پس از اجراي برنامه رخ دهد):
using System;
using System.Reflection;
using System.Runtime.InteropServices;

namespace SigCheck
{
public class Validation
{
[DllImport("mscoree.dll", CharSet = CharSet.Unicode)]
public static extern bool StrongNameSignatureVerificationEx(
string wszFilePath, bool fForceVerification, ref bool pfWasVerified);

public static void SigCheck()
{
var assembly = Assembly.GetExecutingAssembly();
bool pfWasVerified = false;
if (!StrongNameSignatureVerificationEx(assembly.Location, true, ref pfWasVerified))
{
//خاتمه برنامه در صورت عدم وجود امضاي ديجيتال معتبر
throw new Exception();
}
}
}

class Program
{
static void Main(string[] args)
{
Validation.SigCheck();
}
}
}
خوب، شايد پس از حذف و وصله شدن اسمبلي، مجددا strong name به آن اضافه شود! ، آن وقت چه بايد كرد؟
زمانيكه به اسمبلي خود امضاي ديجيتال اضافه مي‌كنيد، هش رمزنگاري شده فايل با الگوريتم RSA ، به همراه public key مورد نياز در اسمبلي ذخيره مي‌شوند. از آنجائيكه private key الگوريتم RSA را منتشر نكرده‌ايد، شكستن الگوريتم RSA كار ساده‌اي نيست، مگر اينكه جفت كليد خودشان را توليد كنند و public key جديد را در فايل نهايي قرار دهند. بديهي است اين public key جديد با كليد عمومي ما كه متناظر است با كليد خصوصي منتشر نشده‌ي اصلي، تطابق نخواهد داشت. براي آشنايي با تابعي كه اين بررسي را انجام مي‌دهد به مقاله ذكر شده رجوع كنيد: