private bool InitKeysOffsets() { CryptoPatches.Clear(); // "N3TableBase - Can't open file(read) File Handle..." var pattern = Pattern.Transform("4E 33 54 61 62 6C 65 42 61 73 65 20 2D 20 43"); // "N3TableBase - C" long offsetLogWrite; if (!Pattern.Find(_data, pattern, out offsetLogWrite)) { Console.WriteLine("[TargetPE::InitKeysOffsets]: Unable to find offset."); return(false); } // Generate pattern for finding all references to that string string logWriteVA = Calculator.OffsetToVA((ulong)offsetLogWrite).ToString("X8"); string logWriteGenPattern = "68"; // push for (int i = logWriteVA.Length - 1; i >= 0; --i) { logWriteGenPattern += i % 2 == 0 ? " " + logWriteVA.Substring(i, 2) : ""; } logWriteGenPattern += " E8"; // call Console.WriteLine($"[TargetPE::InitKeysOffsets]: Generated pattern result: {logWriteGenPattern}"); var patternStrRefRegion = Pattern.Transform(logWriteGenPattern); List <long> regionStrRefOffsets; if (!Pattern.FindAll(_data, patternStrRefRegion, out regionStrRefOffsets)) { Console.WriteLine("[TargetPE::InitKeysOffsets]: No offsets were found."); return(false); } Console.WriteLine($"[TargetPE::InitKeysOffsets]: Found {regionStrRefOffsets.Count} region offsets."); var patDecryptRegions = new Pattern.Byte[][] { // push ?? <- DWORD as short // push ?? <- DWORD as short // push ?? <- DWORD as short Pattern.Transform("68 ?? ?? 00 00 68 ?? ?? 00 00 68 ?? ?? 00 00 ?? ?? E8"), //Pattern.Transform("FF ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 55 FF"), //Pattern.Transform("FF ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 56 FF"), //Pattern.Transform("FF ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 57 FF"), // call ?? <- ReadFile // push ebp|esi|edi // call ?? <- CloseHandle // xor reg,reg Pattern.Transform("FF ?? ?? ?? ?? ?? 55 FF"), Pattern.Transform("FF ?? ?? ?? ?? ?? 56 FF"), Pattern.Transform("FF ?? ?? ?? ?? ?? 57 FF"), }; const int ENCRYPT_REGION_MIN = 50; const int ENCRYPT_REGION_MAX = 700; const int ESTIMATED_DES_RANGE_BYTES = 280; bool detectedDesEncryption = false; foreach (long regionStrRefOffset in regionStrRefOffsets) { long decryptRegionOffset = -1; bool isInlinedFunction = false; for (int i = 0; i < patDecryptRegions.Length; i++) { if (!Pattern.Find(_data, patDecryptRegions[i], out decryptRegionOffset, regionStrRefOffset + ENCRYPT_REGION_MIN, regionStrRefOffset + ENCRYPT_REGION_MAX)) { continue; } // Estimate average distance by bytes, to know whether there is more code for DES encryption before XOR. if (!detectedDesEncryption && (decryptRegionOffset - regionStrRefOffset) > ESTIMATED_DES_RANGE_BYTES) { detectedDesEncryption = true; } // First pattern: we know it's a function that got inlined by the compiler. // +5 for ptr & +2 for xor reg,reg isInlinedFunction = i != 0; if (isInlinedFunction) { CanUpdateKey2 = false; decryptRegionOffset += patDecryptRegions[i].Length + 5 + 2; } break; } if (decryptRegionOffset == -1) { Console.WriteLine($"[TargetPE::InitKeysOffsets]: Unable to find decryption region offset."); continue; } CryptoKey[] keys = new CryptoKey[CryptoPatch.KEYS_COUNT]; MemoryStream ms = (MemoryStream)PE.GetStream(); ms.Seek(decryptRegionOffset, SeekOrigin.Begin); if (isInlinedFunction) { if (!InitInlinedKeys(keys, ms)) { return(false); } } else { for (int i = CryptoPatch.KEYS_COUNT - 1; i >= 0; i--) { DWORD dword; ms.Position++; dword = ms.ReadStructure <DWORD>(); keys[i] = new CryptoKey((ms.Position - 4), (ushort)dword.sValue1, (long)Calculator.OffsetToVA((ulong)(ms.Position - 4))); } } long keyVA = (long)Calculator.OffsetToVA((ulong)decryptRegionOffset); var patch = new CryptoPatch(decryptRegionOffset, keyVA, keys, isInlinedFunction); CryptoPatches.Add(patch); } // Update the container cryption type, so we know what we deal with CryptoPatches.CryptoType = detectedDesEncryption ? CryptoType.DES_XOR : CryptoType.XOR; if (CryptoPatches.Count != regionStrRefOffsets.Count) { return(false); } if (!VerifyAllMatchedKeys(CryptoPatches)) { return(false); } return(true); }
private bool InitClientVersion() { const int MAX_STEPS_FORWARD = 4; const int MIN_CLIENT_VERSION = 1000; const int MAX_CLIENT_VERSION = 5000; var pattern = Pattern.Transform("68 C3 12 00 00"); long offset; if (!Pattern.Find(_data, pattern, out offset)) { Console.WriteLine("[TargetPE::InitClientVersion]: Failed to find resource offset."); return(false); } MemoryStream ms = (MemoryStream)PE.GetStream(); ms.Seek(offset, SeekOrigin.Begin); byte[] buff = new byte[4]; ms.Read(buff, 0, 4, 1); int resourceId = BitConverter.ToInt32(buff, 0); if (resourceId != 4803) { Console.WriteLine($"[TargetPE::InitClientVersion]: Invalid resource id: {resourceId}." + $"Are we at the right location? :)"); return(false); } // https://c9x.me/x86/html/file_module_x86_id_35.html byte[] cmps = { 0x81, 0x3D }; long originOffset = ms.Position; long stepsBack = 72; long startOffset = originOffset - stepsBack; foreach (byte cmp in cmps) { ms.Position = startOffset; // while it's not a compare instruction, keep reading byte bites ;) do { ms.Read(buff, 0, 1); if (ms.Position > originOffset) { return(false); } } while (buff[0] != cmp); for (int i = 0; i < MAX_STEPS_FORWARD; i++) { ms.Read(buff, 0, 4); int version = BitConverter.ToInt32(buff, 0); if (version > MIN_CLIENT_VERSION && version < MAX_CLIENT_VERSION) { ClientVersion = version; Console.WriteLine("[TargetPE::InitClientVersion]: Found client version v" + ClientVersion); return(true); } ms.Position -= 3; } } return(false); }