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); }
private static unsafe bool ProcessSection(LockdownSha1.Context context, LockdownHeap heap, byte *baseaddr, byte *preferredBaseAddr, PeFileReader.ImageSectionHeader *section, int sectionAlignment, int seed) { int eax, virtualAddr, virtualSize, value; int index, bytes; int i; using (HeapPtr hpLockdownMem = heap.ToPointer()) { int * lockdown_memory = (int *)hpLockdownMem.ToPointer(); byte *allocatedMemoryBase; int lowerOffset = (int)baseaddr - (int)preferredBaseAddr; virtualAddr = section->VirtualAddress; virtualSize = section->VirtualSize; bytes = ((virtualSize + sectionAlignment - 1) & ~(sectionAlignment - 1)) - virtualSize; if (section->Characteristics < 0) { LockdownSha1.Pad(context, bytes + virtualSize); } else { index = 0; if (heap.CurrentLength > 0) { for (i = 0; index < heap.CurrentLength && lockdown_memory[i] < virtualAddr; i += 4) { index++; } } if (virtualSize > 0) { byte *startingMemory = baseaddr + virtualAddr; byte *ptrMemory = startingMemory; int memoryOffset = index * 4; do { int sectionLength = (int)(startingMemory - ptrMemory + virtualSize); eax = 0; if (index < heap.CurrentLength) { eax = (int)(lockdown_memory[memoryOffset] + startingMemory - virtualAddr); } if (eax != 0) { eax -= (int)ptrMemory; if (eax < sectionLength) { sectionLength = eax; } } if (sectionLength != 0) { LockdownSha1.Update(context, ptrMemory, sectionLength); ptrMemory += sectionLength; } else { int *heapBuffer = stackalloc int[0x10]; Native.Memcpy((void *)heapBuffer, lockdown_memory + memoryOffset, 0x10); value = (*(int *)ptrMemory - lowerOffset) ^ seed; LockdownSha1.Update(context, (byte *)&value, 4); ptrMemory += heapBuffer[1]; index++; memoryOffset += 4; } } while ((ptrMemory - startingMemory) < virtualSize); } if (bytes > 0) { int i2 = 0; IntPtr memoryAllocation = Marshal.AllocHGlobal(bytes); allocatedMemoryBase = (byte *)memoryAllocation.ToPointer(); Native.Memset(allocatedMemoryBase, 0, bytes); do { eax = 0; if (index < heap.CurrentLength) { value = *(int *)(((byte *)lockdown_memory) + (index * 16)); eax = (int)(value - virtualSize - virtualAddr + allocatedMemoryBase); } bytes += i2; if (eax != 0) { eax -= ((int *)allocatedMemoryBase)[i2 / 4]; if (eax < bytes) { bytes = eax; } } if (bytes != 0) { LockdownSha1.Update(context, &allocatedMemoryBase[i2], bytes); i2 += bytes; } } while (i2 < bytes); Marshal.FreeHGlobal(memoryAllocation); } } } return(true); }