Add code to read win32 resources

This commit is contained in:
de4dot 2011-11-30 18:23:47 +01:00
parent 98342f2a0c
commit 27e7c76636
5 changed files with 361 additions and 5 deletions

View File

@ -29,6 +29,7 @@ namespace de4dot.PE {
SectionHeader[] sectionHeaders;
Cor20Header cor20Header;
SectionHeader dotNetSection;
Resources resources;
public BinaryReader Reader {
get { return reader; }
@ -38,13 +39,18 @@ namespace de4dot.PE {
get { return cor20Header; }
}
public Resources Resources {
get { return resources; }
}
public PeImage(byte[] data)
: this(new MemoryStream(data)) {
}
public PeImage(Stream stream) {
reader = new BinaryReader(stream);
writer = new BinaryWriter(stream);
if (stream.CanWrite)
writer = new BinaryWriter(stream);
init();
}
@ -77,14 +83,20 @@ namespace de4dot.PE {
for (int i = 0; i < sectionHeaders.Length; i++)
sectionHeaders[i] = new SectionHeader(reader);
uint netOffset = optionalHeader.dataDirectories[14].virtualAddress;
if (netOffset != 0) {
seekRva(netOffset);
uint netRva = optionalHeader.dataDirectories[14].virtualAddress;
if (netRva != 0) {
seekRva(netRva);
cor20Header = new Cor20Header(reader);
dotNetSection = getSectionHeader(netOffset);
dotNetSection = getSectionHeader(netRva);
seekRva(cor20Header.metadataDirectory.virtualAddress);
cor20Header.initMetadataTable();
}
uint resourceRva = optionalHeader.dataDirectories[2].virtualAddress;
uint resourceOffset = 0;
if (resourceRva != 0)
resourceOffset = rvaToOffset(resourceRva);
resources = new Resources(reader, resourceOffset, optionalHeader.dataDirectories[2].size);
}
SectionHeader getSectionHeader(uint rva) {
@ -179,6 +191,11 @@ namespace de4dot.PE {
throw new NotImplementedException();
}
public byte offsetReadByte(uint offset) {
seek(offset);
return reader.ReadByte();
}
public ushort offsetReadUInt16(uint offset) {
seek(offset);
return reader.ReadUInt16();

View File

@ -0,0 +1,49 @@
/*
Copyright (C) 2011 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
namespace de4dot.PE {
class ResourceData : ResourceDirectoryEntry {
uint rva;
uint size;
public uint RVA {
get { return rva; }
}
public uint Size {
get { return size; }
}
public ResourceData(int id, uint rva, uint size)
: base(id) {
this.rva = rva;
this.size = size;
}
public ResourceData(string name, uint dataOffset, uint dataSize)
: base(name) {
this.rva = dataOffset;
this.size = dataSize;
}
public override string ToString() {
return string.Format("RVA: {0:X8} SIZE: {1:X8}, NAME: {2}", rva, size, getName());
}
}
}

View File

@ -0,0 +1,124 @@
/*
Copyright (C) 2011 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Collections.Generic;
namespace de4dot.PE {
class ResourceDirectory : ResourceDirectoryEntry {
Resources resources;
int offset;
List<ResourceData> resourceDataList = new List<ResourceData>();
List<ResourceDirectory> resourceDirectoryList = new List<ResourceDirectory>();
public List<ResourceData> Data {
get { return resourceDataList; }
}
public List<ResourceDirectory> Directories {
get { return resourceDirectoryList; }
}
public ResourceDirectory(int id, Resources resources, int offset)
: base(id) {
init(resources, offset);
}
public ResourceDirectory(string name, Resources resources, int offset)
: base(name) {
init(resources, offset);
}
void init(Resources resources, int offset) {
this.resources = resources;
this.offset = offset;
initializeEntries();
}
public ResourceDirectory getDirectory(int id) {
return find(resourceDirectoryList, id);
}
public ResourceDirectory getDirectory(string name) {
return find(resourceDirectoryList, name);
}
public ResourceData getData(int id) {
return find(resourceDataList, id);
}
public ResourceData getData(string name) {
return find(resourceDataList, name);
}
void initializeEntries() {
if (offset < 0)
return;
if (!resources.isSizeAvailable(offset, 16))
return;
if (!resources.seek(offset + 12))
return;
int named = resources.readUInt16();
int ids = resources.readUInt16();
int total = named + ids;
if (!resources.isSizeAvailable(total * 8))
return;
for (int i = 0, entryOffset = offset + 16; i < total; i++, entryOffset += 8) {
resources.seek(entryOffset);
uint nameOrId = resources.readUInt32();
uint dataOrDirectory = resources.readUInt32();
string name = null;
int id = -1;
if ((nameOrId & 0x80000000) != 0) {
name = resources.readString((int)(nameOrId & 0x7FFFFFFF));
if (name == null)
break;
}
else
id = (int)nameOrId;
if ((dataOrDirectory & 0x80000000) == 0) {
if (!resources.seek((int)dataOrDirectory))
break;
if (!resources.isSizeAvailable(16))
break;
uint dataRva = resources.readUInt32();
uint dataSize = resources.readUInt32();
if (name == null)
resourceDataList.Add(new ResourceData(id, dataRva, dataSize));
else
resourceDataList.Add(new ResourceData(name, dataRva, dataSize));
}
else {
int directoryOffset = (int)(dataOrDirectory & 0x7FFFFFFF);
if (name == null)
resourceDirectoryList.Add(new ResourceDirectory(id, resources, directoryOffset));
else
resourceDirectoryList.Add(new ResourceDirectory(name, resources, directoryOffset));
}
}
}
public override string ToString() {
return string.Format("OFS: {0:X8}, NAME: {1}", offset, getName());
}
}
}

View File

@ -0,0 +1,73 @@
/*
Copyright (C) 2011 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Collections.Generic;
namespace de4dot.PE {
abstract class ResourceDirectoryEntry {
protected readonly string name;
protected readonly int id;
public bool HasStringName {
get { return name != null; }
}
public bool HasId {
get { return !HasStringName; }
}
public string Name {
get { return name; }
}
public int Id {
get { return id; }
}
public ResourceDirectoryEntry(int id) {
this.name = null;
this.id = id;
}
public ResourceDirectoryEntry(string name) {
this.name = name;
this.id = -1;
}
protected string getName() {
return HasStringName ? name : id.ToString();
}
protected static T find<T>(IEnumerable<T> list, int id) where T : ResourceDirectoryEntry {
foreach (var dirEntry in list) {
if (dirEntry.HasId && dirEntry.Id == id)
return dirEntry;
}
return null;
}
protected static T find<T>(IEnumerable<T> list, string name) where T : ResourceDirectoryEntry {
foreach (var dirEntry in list) {
if (dirEntry.HasStringName && dirEntry.Name == name)
return dirEntry;
}
return null;
}
}
}

View File

@ -0,0 +1,93 @@
/*
Copyright (C) 2011 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System.IO;
using System.Text;
namespace de4dot.PE {
class Resources {
BinaryReader reader;
uint startOffset;
uint totalSize;
ResourceDirectory root;
public BinaryReader Reader {
get { return reader; }
}
public Resources(BinaryReader reader, uint startOffset, uint totalSize) {
this.reader = reader;
this.startOffset = startOffset;
this.totalSize = totalSize;
}
public ResourceDirectory getRoot() {
if (root != null)
return root;
return root = new ResourceDirectory("root", this, startOffset == 0 ? -1 : 0);
}
public bool isSizeAvailable(int offset, int size) {
if (offset < 0 || offset + size < offset)
return false;
return (uint)(offset + size) <= totalSize;
}
public bool isSizeAvailable(int size) {
return isSizeAvailable((int)(reader.BaseStream.Position - startOffset), size);
}
public bool seek(int offset) {
if (!isSizeAvailable(offset, 0))
return false;
reader.BaseStream.Position = startOffset + offset;
return true;
}
public ushort readUInt16() {
return reader.ReadUInt16();
}
public uint readUInt32() {
return reader.ReadUInt32();
}
public byte[] readBytes(int size) {
return reader.ReadBytes(size);
}
public string readString(int offset) {
if (!seek(offset))
return null;
if (!isSizeAvailable(2))
return null;
int size = readUInt16();
int sizeInBytes = size * 2;
if (!isSizeAvailable(sizeInBytes))
return null;
var stringData = readBytes(sizeInBytes);
try {
return Encoding.Unicode.GetString(stringData);
}
catch {
return null;
}
}
}
}