internal unsafe static bool HashFile(LockdownSha1.Context context, string filename, int seed) { int i, headersSize, sectionAlignment; byte * imageBase; PeFileLoader module; byte * firstSection; byte * baseaddr; //PeFileReader.NtHeaders.ImageDataDirectory* importDir; PeFileReader.NtHeaders.ImageDataDirectory *relocDir; PeFileReader.DosImageHeader *dosheader; PeFileReader.NtHeaders * ntheader; LockdownHeap heap = new LockdownHeap(); module = new PeFileLoader(filename); baseaddr = module.BaseAddress; dosheader = (PeFileReader.DosImageHeader *)baseaddr; ntheader = (PeFileReader.NtHeaders *)(baseaddr + dosheader->e_lfanew); sectionAlignment = ntheader->OptionalHeader.SectionAlignment; imageBase = (byte *)ntheader->OptionalHeader.ImageBase; //importDir = (PeFileReader.NtHeaders.ImageDataDirectory*)&ntheader->OptionalHeader.IDD1; relocDir = (PeFileReader.NtHeaders.ImageDataDirectory *) & ntheader->OptionalHeader.IDD5; // roughly, IMAGE_FIRST_SECTION macro. 0x18 is the offset of the optional header, plus size of optional header. firstSection = (byte *)(((byte *)ntheader) + 0x18 + ntheader->SizeOfOptionalHeader); headersSize = ntheader->OptionalHeader.SizeOfHeaders; LockdownSha1.Update(context, baseaddr, headersSize); if (relocDir->VirtualAddress != 0 && relocDir->Size != 0) { if (!ProcessRelocDir(heap, baseaddr, relocDir)) { module.Dispose(); heap = null; return(false); } } for (i = 0; i < (ntheader->NumberOfSections); i++) { if (!ProcessSection(context, heap, baseaddr, imageBase, (PeFileReader.ImageSectionHeader *)(firstSection + (i * 0x28)), sectionAlignment, seed)) { module.Dispose(); heap = null; return(false); } } heap = null; module.Dispose(); return(true); }
/// <summary> /// Calculates the lockdown checkrevision. /// </summary> /// <param name="file1">The first game file</param> /// <param name="file2">The second game file</param> /// <param name="file3">The third game file</param> /// <param name="valueString">The value calculation string from the server</param> /// <param name="version">The version</param> /// <param name="checksum">The checksum</param> /// <param name="digest">The result</param> /// <param name="lockdownFile">The name of the lockdown file</param> /// <param name="imageDump">The path to the screen dump</param> /// <returns></returns> public static unsafe bool CheckRevision(string file1, string file2, string file3, byte[] valueString, ref int version, ref int checksum, out byte[] digest, string lockdownFile, string imageDump) { int returnIsValid = 1; int moduleOffset = 0; int seed, i; digest = null; int digit = GetDigit(lockdownFile); seed = seeds[digit]; version = PeFileLoader.GetVersion(file1); // note that the HeapPtr can be implicitly cast to byte* and so therefore // can be used in method calls that would normally accept a byte* parameter. using (HeapPtr pSha1Buf = new HeapPtr(20, AllocMethod.HGlobal)) using (HeapPtr pSha1Buf2 = new HeapPtr(20, AllocMethod.HGlobal)) using (HeapPtr pValStr = new HeapPtr(valueString.Length, AllocMethod.HGlobal)) using (HeapPtr pValStrEnc = new HeapPtr(valueString.Length, AllocMethod.HGlobal)) using (HeapPtr pValStrBuffer1 = new HeapPtr(0x40, AllocMethod.HGlobal)) using (HeapPtr pValStrBuffer2 = new HeapPtr(0x40, AllocMethod.HGlobal)) using (HeapPtr pTempMem = new HeapPtr(16, AllocMethod.HGlobal)) using (HeapPtr pDigest = new HeapPtr(17, AllocMethod.HGlobal)) { pValStr.MarshalData(valueString); if (!ShuffleValueString(pValStr, valueString.Length, pValStrEnc)) { return(false); } Native.Memset(pValStrBuffer1.ToPointer(), 0x36, 0x40); Native.Memset(pValStrBuffer2.ToPointer(), 0x5c, 0x40); byte *valuestrBuffer1 = pValStrBuffer1; byte *valuestrBuffer2 = pValStrBuffer2; byte *valueStrEncoded = pValStrEnc; for (i = 0; i < 0x10; i++) { valuestrBuffer1[i] ^= valueStrEncoded[i]; valuestrBuffer2[i] ^= valueStrEncoded[i]; } LockdownSha1.Context context = LockdownSha1.Init(); LockdownSha1.Update(context, valuestrBuffer1, 0x40); if (!HashFile(context, lockdownFile, seed)) { return(false); } if (!HashFile(context, file1, seed)) { return(false); } if (!HashFile(context, file2, seed)) { return(false); } if (!HashFile(context, file3, seed)) { return(false); } LockdownSha1.HashFile(context, imageDump); LockdownSha1.Update(context, (byte *)&returnIsValid, 4); LockdownSha1.Update(context, (byte *)&moduleOffset, 4); LockdownSha1.Final(context, pSha1Buf); context = LockdownSha1.Init(); LockdownSha1.Update(context, pValStrBuffer2, 0x40); LockdownSha1.Update(context, pSha1Buf, 0x14); LockdownSha1.Final(context, pSha1Buf2); checksum = *(int *)((byte *)pSha1Buf2); Native.Memmove(pTempMem, ((byte *)pSha1Buf2) + 4, 0x10); int valstrLen = 0xff; if (!CalculateDigest(pDigest, ref valstrLen, pTempMem)) { return(false); } ((byte *)pDigest)[valstrLen] = 0x00; digest = new byte[valstrLen]; Marshal.Copy(new IntPtr(pDigest.ToPointer()), digest, 0, valstrLen); } return(true); }