public unsafe void DeLocateBuff32(byte[] bytes, uint Delta, uint RVA, Reloc[] relocs) { // round down to page alignment var xVA = RVA & ~4095u; byte* basep; if (relocs == null) return; fixed(byte* bp = bytes) { for (int i = 0; i < relocs.Length; i++) { if (relocs[i].PageRVA == xVA) { // ANY OVERHANG FROM (LAST-VA == VA-4096), use, otherwise ignore if (OverHang != 0 && (xVA - 4096) == OverHang) { var _3bp = bp; // have only written 1 byte in the previous page switch (OvrOffset) { case 1: if (CarryOne) b = (byte)(*_3bp - 1); else b = *_3bp; CarryOne = b < ((Delta & 0x0000FF00) >> 8) ? true : false; *_3bp = (byte)(b - ((Delta & 0xFF00) >> 8)); _3bp++; if (CarryOne) b = (byte)(*_3bp - 1); else b = *_3bp; CarryOne = b < ((Delta & 0x00FF0000) >> 16) ? true : false; *_3bp = (byte)(b - ((Delta & 0x00FF0000) >> 16)); _3bp++; if (CarryOne) b = (byte)(*_3bp - 1); else b = *_3bp; CarryOne = b < ((Delta & 0xFF000000) >> 24) ? true : false; *_3bp = (byte)(b - ((Delta & 0xFF000000) >> 24)); break; case 2: if (CarryOne) b = (byte)(*_3bp - 1); else b = *_3bp; CarryOne = b < ((Delta & 0x00FF0000) >> 16) ? true : false; *_3bp = (byte)(b - ((Delta & 0x00FF0000) >> 16)); _3bp++; if (CarryOne) b = (byte)(*_3bp - 1); else b = *_3bp; CarryOne = b < ((Delta & 0xFF000000) >> 24) ? true : false; *_3bp = (byte)(b - ((Delta & 0xFF000000) >> 24)); break; case 3: if (CarryOne) b = (byte)(*_3bp - 1); else b = *_3bp; CarryOne = b < ((Delta & 0xFF000000) >> 24) ? true : false; *_3bp = (byte)(b - ((Delta & 0xFF000000) >> 24)); break; default: break; } // reset overhang OverHang = 0; CarryOne = false; } for (int j = 0; j < relocs[i].Area.Length; j++) { // their can be a trailing null entry sometimes if (relocs[i].Area[j] == 0) continue; // 4KB max limit var offset = (relocs[i].Area[j]) & 0xFFFu; // trim offset if we are unaligned reading if (RVA != xVA) { var Unaligned = RVA - xVA; // this reloc entry is for an earlier/unaligned page if (offset < Unaligned) continue; offset -= Unaligned; } // reset to base pointer every fixup basep = bp; // get byte offset basep += offset; // WRITE 4 if (offset < 4093) { // get int* to byte offset var intp = (uint*)basep; var curr = *intp; // this has got to be an error //if(curr == 0) //Console::WriteLine("B00G"); *intp = curr - Delta; OvrOffset = 0; } else { var _3bp = basep; OverHang = xVA; OvrOffset = (int)(4096 - offset); switch (offset) { // WRITE 3 case 4093: { b = *_3bp; CarryOne = b < (Delta & 0x000000FF) ? true : false; *_3bp = (byte)(b - (Delta & 0x000000FF)); _3bp++; if (CarryOne) b = (byte)(*_3bp - 1); else b = *_3bp; CarryOne = b < ((Delta & 0x0000FF00) >> 8) ? true : false; *_3bp = (byte)(b - ((Delta & 0x0000FF00) >> 8)); _3bp++; if (CarryOne) b = (byte)(*_3bp - 1); else b = *_3bp; CarryOne = b < ((Delta & 0x00FF0000) >> 16) ? true : false; *_3bp = (byte)(b - ((Delta & 0x00FF0000) >> 16)); break; } // WRITE 2 case 4094: { b = *_3bp; CarryOne = b < (Delta & 0x000000FF) ? true : false; *_3bp = (byte)(b - (Delta & 0x000000FF)); _3bp++; if (CarryOne) b = (byte)(*_3bp - 1); else b = *_3bp; CarryOne = b < ((Delta & 0x0000FF00) >> 8) ? true : false; *_3bp = (byte)(b - ((Delta & 0x0000FF00) >> 8)); _3bp++; break; } // WRITE 1 case 4095: { b = *_3bp; CarryOne = b < (Delta & 0x000000FF) ? true : false; *_3bp = (byte)(b - ((Delta & 0x000000FF))); break; } default: break; } } } } } } }
/// <summary> /// This routine takes a binary .reloc and emit's List of type Reloc /// /// There are theoretically some .reloc entries we do not support, I've not seen too many for recent binaries. /// /// If we wanted to support more, adding more translations here would be fine. /// </summary> /// <param name="FileBuff"></param> /// <returns></returns> public static List<Reloc> ProcessRelocs(byte[] FileBuff) { var rv = new List<Reloc>(); using (var ms = new MemoryStream(FileBuff)) using (var reReader = new BinaryReader(ms)) { var pageRVA = reReader.ReadUInt32(); var blockSize = reReader.ReadInt32(); var BlockPos = ms.Position; var Count = (blockSize - 8) / 2; while (blockSize != 0) { var rl = new Reloc { PageRVA = pageRVA, BlockSize = blockSize, Area = new ushort[Count] }; for (int i = 0; i < Count; i++) rl.Area[i] = reReader.ReadUInt16(); rv.Add(rl); pageRVA = reReader.ReadUInt32(); if (pageRVA == 0) break; blockSize = reReader.ReadInt32(); if (blockSize == 0) break; Count = (blockSize - 8) / 2; } } return rv; }