8000 Restructure of a lot of the internal code to remove Windows API depen… · coderforlife/pe-file@0c74d2c · GitHub
[go: up one dir, main page]

Skip to content

Commit 0c74d2c

Browse files
committed
Restructure of a lot of the internal code to remove Windows API dependencies along with licensing under GPL.
Removed ustl and am now just using standard stl. Added PEVersion to completely replace use of VerQueryValue. Abstracted out data source so memory-mapped files and in-memory data can be used more seamlessly. Added POSIX code to use when Win API is not available. The POSIX code is untested but it should be mostly there.
1 parent 1776273 commit 0c74d2c

21 files changed

+1784
-1603
lines changed

PEDataSource.cpp

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
// pe-file: library for reading and manipulating pe-files
2+
// Copyright (C) 2012 Jeffrey Bush jeff@coderforlife.com
3+
//
4+
// This library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
18+
#ifdef __cplusplus_cli
19+
#pragma unmanaged
20+
#endif
21+
#include "PEDataSource.h"
22+
23+
#include <stdlib.h>
24+
#include <memory.h>
25+
26+
#ifdef USE_WINDOWS_API
27+
#ifdef ARRAYSIZE
28+
#undef ARRAYSIZE
29+
#endif
30+
#define WIN32_LEAN_AND_MEAN
31+
#include <Windows.h>
32+
#else
33+
#include <sys/mman.h>
34+
#include <sys/stat.h>
35+
#endif
36+
37+
using namespace PE;
38+
39+
RawDataSource::RawDataSource(pntr data, size_t size, bool readonly) : readonly(readonly), orig_data(data), sz(size) {
40+
if (readonly) {
41+
#ifdef USE_WINDOWS_API
42+
DWORD old_protect = 0;
43+
if ((this->d = (bytes)VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)) == NULL ||
44+
memcpy(this->d, this->orig_data, size) == NULL || !VirtualProtect(this->d, size, PAGE_READONLY, &old_protect)) { this->close(); }
45+
#else
46+
if ((this->d = (bytes)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) == MAP_FAILED ||
47+
memcpy(this->d, this->orig_data, size) == NULL || mprotect(this->d, size, PROT_READ) == -1) { if (this->d == MAP_FAILED) { this->d = NULL; } this->close(); }
48+
#endif
49+
} else {
50+
this->d = this->orig_data;
51+
}
52+
}
53+
RawDataSource::~RawDataSource() { this->close(); }
54+
bool RawDataSource::isreadonly() const { return this->readonly; };
55+
bool RawDataSource::flush() { return true; }
56+
pntr RawDataSource::data() { return this->d; }
57+
size_t RawDataSource::size() const { return this->sz; }
58+
void RawDataSource::close() {
59+
if (this->d) {
60+
this->flush();
61+
if (this->readonly) {
62+
#ifdef USE_WINDOWS_API
63+
VirtualFree(this->d, 0, MEM_RELEASE);
64+
#else
65+
munmap(this->d, this->sz);
66+
#endif
67+
}
68+
this->d = NULL;
69+
}
70+
if (this->orig_data) { free(this->orig_data); this->orig_data = NULL; }
71+
this->sz = 0;
72+
}
73+
bool RawDataSource::resize(size_t new_size) {
74+
if (this->readonly) { return false; }
75+
if (new_size == this->sz) { return true; }
76+
this->flush();
77+
this->d = (bytes)realloc(this->orig_data, new_size);
78+
if (!this->d) { this->close(); return false; }
79+
this->orig_data = this->d;
80+
if (new_size < this->sz)
81+
memset((bytes)this->d+this->sz, 0, new_size-this->sz); // set new memory to 0
82+
this->sz = new_size;
83+
return true;
84+
}
85+
86+
#pragma region Memory Map Management Functions
87+
///////////////////////////////////////////////////////////////////////////////
88+
///// Memory Map Management Functions
89+
///////////////////////////////////////////////////////////////////////////////
90+
#include <map>
91+
#include <vector>
92+
using namespace std;
93+
typedef map<const_str, vector<pntr> > MMFs;
94+
static MMFs mmfs;
95+
static void _RemoveMMF(MMFs &mmfs, const_str file, pntr x) {
96+
MMFs::iterator v = mmfs.find(file);
97+
if (v != mmfs.end()) {
98+
size_t size = v->second.size();
99+
for (size_t i = 0; i < size; ++i) {
100+
if (v->second[i] == x) {
101+
if (size == 1) {
102+
mmfs.erase(v);
103+
} else {
104+
if (i != size-1) // move the last element up
105+
v->second[i] = v->second[size-1];
106+
v->second.pop_back(); // remove the last element
107+
}
108+
break;
109+
}
110+
}
111+
}
112+
}
113+
static pntr AddMMF (const_str file, pntr mm) { if (mm != NULL && mm != (pntr)-1) { mmfs[file].push_back(mm); } return mm; }
114+
static void RemoveMMF(const_str file, pntr mm) { _RemoveMMF(mmfs, file, mm); }
115+
116+
#ifdef USE_WINDOWS_API
117+
static MMFs mmfViews;
118+
typedef BOOL (WINAPI *UNMAP_OR_CLOSE)(void*);
119+
static pntr AddMMFView(const_str file, pntr view) { if (view != NULL) mmfViews[file].push_back(view); return view; }
120+
static void RemoveMMFView(const_str file, pntr view) { _RemoveMMF(mmfViews, file, view); }
121+
static void _UnmapAll(MMFs &mmfs, const_str file, UNMAP_OR_CLOSE func) {
122+
MMFs::iterator v = mmfs.find(file);
123+
if (v != mmfs.end()) {
124+
size_t size = v->second.size();
125+
for (size_t i = 0; i < size; ++i)
126+
func(v->second[i]);
127+
mmfs.erase(v);
128+
}
129+
}
130+
void MemoryMappedDataSource::UnmapAllViewsOfFile(const_str file) {
131+
_UnmapAll(mmfs, file, &CloseHandle);
132+
_UnmapAll(mmfViews, file, (UNMAP_OR_CLOSE)&UnmapViewOfFile);
133+
}
134+
#else
135+
void MemoryMappedDataSource::UnmapAllViewsOfFile(const_str file) {
136+
MMFs::iterator v = mmfs.find(file);
137+
if (v != mmfs.end()) {
138+
size_t size = v->second.size();
139+
for (size_t i = 0; i < size; ++i)
140+
munmap(v->second[i]);
141+
mmfs.erase(v);
142+
}
143+
}
144+
#endif
145+
#pragma endregion
146+
147+
bool MemoryMappedDataSource::map() {
148+
#ifdef USE_WINDOWS_API
149+
return
150+
(this->hMap = AddMMF(this->original, CreateFileMapping(this->hFile, NULL, (readonly ? PAGE_READONLY : PAGE_READWRITE), 0, 0, NULL))) != NULL &&
151+
(this->d = AddMMFView(this->original, MapViewOfFile(this->hMap, (readonly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS), 0, 0, 0))) != NULL;
152+
#else
153+
return (this->d = AddMMF(this->original, mmap(NULL, this->sz, (readonly ? PROT_READ : PROT_READ | PROT_WRITE), (readonly ? MAP_PRIVATE : MAP_SHARED), this->fd, 0))) != MAP_FAILED;
154+
#endif
155+
}
156+
void MemoryMappedDataSource::unmap() {
157+
#ifdef USE_WINDOWS_API
158+
if (this->hMap) {
159+
if (this->d)
160+
{
161+
this->flush();
162+
UnmapViewOfFile(this->d);
163+
RemoveMMFView(this->original, this->d);
164+
this->d = NULL;
165+
}
166+
RemoveMMF(this->original, this->hMap);
167+
CloseHandle(this->hMap);
168+
this->hMap = NULL;
169+
}
170+
#else
171+
if (this->d == MAP_FAILED) { this->d = NULL; }
172+
else if (this->d)
173+
{
174+
this->flush();
175+
munmap(this->d, this->sz);
176+
RemoveMMF(this->original, this->d);
177+
this->d = NULL;
178+
}
179+
#endif
180+
}
181+
#ifdef USE_WINDOWS_API
182+
MemoryMappedDataSource::MemoryMappedDataSource(const_str file, bool readonly) : readonly(readonly), hFile(INVALID_HANDLE_VALUE), hMap(NULL), d(NULL), sz(0) {
183+
#else
184+
MemoryMappedDataSource::MemoryMappedDataSource(const_str file, bool readonly) : readonly(readonly), fd(-1), d(NULL), sz(0) {
185+
#endif
186+
this->original[0] = 0;
187+
#ifdef USE_WINDOWS_API
188+
if (!GetFullPathName(file, ARRAYSIZE(this->original), this->original, NULL) ||
189+
(this->hFile = CreateFile(this->original, (readonly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE)), FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE ||
190+
(this->sz = GetFileSize(this->hFile, 0)) == INVALID_FILE_SIZE)
191+
{
192+
this->close();
193+
}
194+
#else
195+
struct stat sb;
196+
if ((_wrealpath(file, this->original) == NULL) ||
197+
(this->fd = _wopen(this->original, (readonly ? O_RDONLY : O_RDWR))) == -1 ||
198+
fstat(this->fd, &sb) == -1)
199+
{
200+
this->close();
201+
}
202+
this->sz = sb.st_size;
203+
#endif
204+
if (!map())
205+
this->close();
206+
}
207+
MemoryMappedDataSource::~MemoryMappedDataSource() { this->close(); }
208+
209+
bool MemoryMappedDataSource::isreadonly() const { return this->readonly; };
210+
bool MemoryMappedDataSource::flush() {
211+
#ifdef USE_WINDOWS_API
212+
return !this->readonly && FlushViewOfFile(this->d, 0) && FlushFileBuffers(this->hFile);
213+
#else
214+
return !this->readonly && msync(this->d, this->sz, MS_SYNC | MS_INVALIDATE) != -1;
215+
#endif
216+
}
217+
218+
pntr MemoryMappedDataSource::data() { return this->d; }
219+
size_t MemoryMappedDataSource::size() const { return this->sz; }
220+
void MemoryMappedDataSource::close() {
221+
this->unmap();
222+
#ifdef USE_WINDOWS_API
223+
if (this->hFile != INVALID_HANDLE_VALUE) { CloseHandle(this->hFile); this->hFile = INVALID_HANDLE_VALUE; }
224+
#else
225+
if (this->fd != -1) { close(this->fd); this->fd = -1; }
226+
#endif
227+
this->sz = 0;
228+
}
229+
bool MemoryMappedDataSource::resize(size_t new_size) {
230+
if (this->readonly) { return false; }
231+
if (new_size == this->sz) { return true; }
232+
this->unmap();
233+
#ifdef USE_WINDOWS_API
234+
if (SetFilePointer(this->hFile, (uint32_t)new_size, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER || !SetEndOfFile(this->hFile) || !this->map()) { this->close(); return false; }
235+
if (new_size > this->sz)
236+
memset((bytes)this->d+this->sz, 0, new_size-this->sz); // set new memory to 0 (I am unsure if Windows does this automatically like Linux does)
237+
#else
238+
if (ftruncate(this->fd, new_size) == -1 || !this->map()) { this->close(); return false; }
239+
#endif
240+
this->sz = new_size;
241+
return true;
242+
}

PEDataSource.h

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// pe-file: library for reading and manipulating pe-files
2+
// Copyright (C) 2012 Jeffrey Bush jeff@coderforlife.com
3+
//
4+
// This library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
// Implements the classes and functions for reading and writing data
18+
19+
#ifndef PE_DATA_SOURCE_H
20+
#define PE_DATA_SOURCE_H
21+
22+
#include "PEDataTypes.h"
23+
24+
#include <stdlib.h>
25+
26+
namespace PE {
27+
class DataSourceImp {
28+
public:
29+
virtual bool isreadonly() const = 0;
30+
virtual void close() = 0;
31+
virtual bool flush() = 0;
32+
virtual pntr data() = 0;
33+
virtual size_t size() const = 0;
34+
virtual bool resize(size_t new_size) = 0;
35+
};
36+
37+
class RawDataSource : public DataSourceImp {
38+
bool readonly;
39+
pntr d, orig_data;
40+
size_t sz;
41+
public:
42+
RawDataSource(pntr data, size_t size, bool readonly = false);
43+
~RawDataSource();
44+
virtual bool isreadonly() const;
45+
virtual pntr data();
46+
virtual size_t size() const;
47+
virtual void close();
48+
virtual bool resize(size_t new_size);
49+
virtual bool flush();
50+
};
51+
52+
class MemoryMappedDataSource : public DataSourceImp {
53+
bool readonly;
54+
wchar_t original[LARGE_PATH];
55+
#ifdef USE_WINDOWS_API
56+
pntr hFile, hMap;
57+
#else
58+
int fd;
59+
#endif
60+
pntr d;
61+
size_t sz;
62+
63+
bool map();
64+
void unmap();
65+
public:
66+
MemoryMappedDataSource(const_str file, bool readonly = false);
67+
~MemoryMappedDataSource();
68+
virtual bool isreadonly() const;
69+
virtual pntr data();
70+
virtual size_t size() const;
71+
virtual void close();
72+
virtual bool resize(size_t new_size);
73+
virtual bool flush();
74+
75+
static void UnmapAllViewsOfFile(const_str file);
76+
};
77+
78+
class DataSource {
79+
DataSourceImp* ds;
80+
bool readonly;
81+
pntr data;
82+
size_t sz;
83+
84+
inline void update() {
85+
if (this->ds) { this->data = this->ds->data(); this->sz = this->ds->size(); }
86+
else { this->data = NULL; this->sz = 0; }
87+
}
88+
89+
public:
90+
inline DataSource(DataSourceImp* ds) : ds(ds), readonly(ds && ds->isreadonly()), data(ds ? ds->data() : NULL), sz(ds ? ds->size() : 0) { }
91+
//inline static DataSource create(pntr data, size_t size, bool readonly = false) { return DataSource(new RawDataSource(data, size, readonly)); }
92+
//inline static DataSource create(const_str file, bool readonly = false) { return DataSource(new MemoryMappedDataSource(file, readonly)); }
93+
94+
inline bool isopen() const { return this->data != NULL; }
95+
inline bool isreadonly() const { return this->readonly; }
96+
97+
inline size_t size() const { return this->sz; }
98+
99+
inline bool flush() { return this->ds->flush(); }
100+
inline void close() { if (this->ds) { this->ds->close(); delete this->ds; this->ds = NULL; this->update(); } }
101+
inline bool resize(size_t new_size) { bool retval = this->ds->resize(new_size); if (retval) { this->update(); } return retval; }
102+
103+
//inline operator bool() const { return this->data != NULL; } // returns if the data is open
104+
105+
//inline operator pntr() { return this->data; }
106+
//inline operator bytes() { return (bytes)this->data; }
107+
//inline operator const_pntr() const { return this->data; }
108+
//inline operator const_bytes() const { return (const_bytes)this->data; }
109+
110+
inline bytes operator +(const size_t& off) { return ((bytes)this->data) + off; }
111+
inline const_bytes operator +(const size_t& off) const { return ((const_bytes)this->data) + off; }
112+
113+
inline ptrdiff_t operator -(const_bytes b) const { return (const_bytes)this->data - b; }
114+
115+
inline byte& operator[](const size_t& off) { return ((bytes)this->data)[off]; }
116+
inline const byte& operator[](const size_t& off) const { return ((const_bytes)this->data)[off]; }
117+
};
118+
119+
inline ptrdiff_t operator -(const_bytes a, const DataSource& b) { return a - (b + 0); }
120+
}
121+
122+
123+
#endif

0 commit comments

Comments
 (0)
0