resedit 1.8 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d5bb82eb4e37c29d800e45d61d1fd8359afb224d
4
- data.tar.gz: 206c81a15f6e4bc8f50893ce9c8900fb89ec4ad4
3
+ metadata.gz: 7e951763342994ca2eb391febf485c7af0b61b6d
4
+ data.tar.gz: 46699aaad4668d939f3a8bf5475d141aead053e4
5
5
  SHA512:
6
- metadata.gz: c28f9d26f1e08a3980b254ada58e772a2a65efec98ca6e4b9008625ca1f7790a61777d9dd882a618c001abcfa3a71b9d07ecacaf321c176fcfcbcb3f90d713cd
7
- data.tar.gz: 05c2a94a3fba256b35e624d2477678d3210a3009f994fa347f500afae29dbbb7eabe79789ade857336e9ed1ecb9ab872da30d58b6ebe1d3bcf3c93de71716ce0
6
+ metadata.gz: e51ae58c40d9aa5ea3704696256c5f8d1fa408dca322c77e3dd1264f776a0dcceb2ed27c2a1e2bb60b386f0f20375ea705a328ef68257b009c09ca6e8bc07316
7
+ data.tar.gz: 2561a3233ec457ac8de1035549228eeb3bead6ead35687c1fff12df9c3efb630572f08fb48767744128287b80d790c29df4ffcb78df8d54b25181377959ff60e
data/lib/resedit.rb CHANGED
@@ -25,5 +25,5 @@ require 'resedit/mz/multiexe'
25
25
 
26
26
 
27
27
  module Resedit
28
- VERSION = "1.8"
28
+ VERSION = "1.8.1"
29
29
  end
@@ -23,11 +23,14 @@ module Resedit
23
23
  "append"=>[method(:append), "add bytes to current file", {"value" => "value", "type" => "value type", "where" => "append offset. default: above ss:sp"}],
24
24
  "replace"=>[method(:replace), "replace added bytes", {"value" => "value", "type"=>"value type"}],
25
25
  "change"=>[method(:change), "change bytes at offset", {"ofs" => "data ofset", "value" => "value", "disp" => "code/file", "type"=>"value type"}],
26
- "reloc"=>[method(:reloc), "add relocation", {"value" => "value"}],
26
+ "reloc"=>[method(:reloc), "add relocation", {"offset" => "reloc offset", "target" => "address reloc points to"}],
27
27
  "revert"=>[method(:revert), "revert changes", {"ofs"=>"change offset/all"}],
28
28
  "hex"=>[method(:hex), "print hex file", {"ofs" => "data offset", "size" => "data size", "how"=>"original/modified", "disp" => "code/file"}],
29
29
  "dasm"=>[method(:dasm), "print disasm", {"ofs" => "data offset", "size" => "data size", "how"=>"original/modified"}],
30
30
  "eval"=>[method(:expr), "print expression", {"expr" => "expression"}],
31
+ "dump"=>[method(:dump), "dump exe parts", {"out" => "output filename", "parts"=>"list of parts", "how"=>"original/modified"}],
32
+ "relocfind"=>[method(:relocfind), "find relocation with value", {"value" => "value", "type"=>"value type"}],
33
+ "stringfind"=>[method(:stringfind), "search for strings in exe", {"size"=>"min string size"}],
31
34
  }
32
35
  @shorters = {"p"=>"print", "e"=>"eval"}
33
36
  @files = []
@@ -144,7 +147,15 @@ module Resedit
144
147
  end
145
148
 
146
149
  def reloc(params)
147
- cur().reloc(params['value'])
150
+ cur().reloc(params['offset'],params['target'])
151
+ end
152
+
153
+ def relocfind(params)
154
+ cur().relocfind(params['value'], params['type'])
155
+ end
156
+
157
+ def stringfind(params)
158
+ cur().stringfind(params['size'])
148
159
  end
149
160
 
150
161
  def revert(params)
@@ -166,6 +177,10 @@ module Resedit
166
177
  puts env.s2i(params['expr'])
167
178
  end
168
179
 
180
+ def dump(params)
181
+ cur().dump(params['out'], params['parts'], params['how'])
182
+ end
183
+
169
184
 
170
185
  def job(params)
171
186
  cmd = params['cmd']
@@ -1,24 +1,41 @@
1
1
  require 'resedit/app/io_commands'
2
+ require 'resedit/app/app_command'
2
3
 
3
4
  module Resedit
4
5
 
6
+ class ITextConvert < AppCommand
7
+ attr_accessor :text
8
+ def initialize(resname, params)
9
+ @resname, @params = resname, params
10
+ end
11
+ def mktext(file, format, encoding); raise "NotImplemented" end
12
+ def expectedLines(file); raise "NotImplemented" end
13
+ def pack(file, outstream); raise "NotImplemented" end
14
+ def unpack(file); raise "NotImplemented" end
15
+ end
16
+
5
17
  class TextConvertCommand < ConvertCommand
6
18
 
19
+
20
+ attr_accessor :text
7
21
  def initialize(fname, cmdname='text')
8
22
  super(cmdname, fname)
9
- @font = nil
23
+ @text = nil
10
24
  addOption('format','f',nil,'output file format')
11
25
  addOption('encoding','e',nil,'output file encoding')
12
26
  end
13
27
 
28
+ def getInterface(resname, params); self end
29
+
14
30
  def import(inname)
31
+ @iface = getInterface(@resname, @params)
15
32
  logd("importing text #{inname} to #{@resname}")
16
33
  back = backup()
17
34
  File.open(back,"rb"){|file|
18
- @text = mktext(file, @params['format'], @params['encoding'])
19
- @text.load(inname, expectedLines())
35
+ @iface.text = @iface.mktext(file, @params['format'], @params['encoding'])
36
+ @iface.text.load(inname, @iface.expectedLines())
20
37
  StringIO.open("","w+b"){|stream|
21
- pack(file, stream)
38
+ @iface.pack(file, stream)
22
39
  stream.seek(0)
23
40
  File.open(@resname,"wb"){|out|
24
41
  out.write(stream.read())
@@ -29,13 +46,14 @@ module Resedit
29
46
 
30
47
 
31
48
  def export(outname)
49
+ @iface = getInterface(@resname, @params)
32
50
  logd("exporting text #{@resname} to #{outname}")
33
51
  File.open(@resname, "rb"){|file|
34
- @text = mktext(file, @params['format'], @params['encoding'])
35
- unpack(file) if @text
52
+ @iface.text = @iface.mktext(file, @params['format'], @params['encoding'])
53
+ @iface.unpack(file) if @iface.text
36
54
  }
37
- raise "Text not unpacked" if !@text
38
- @text.save(outname)
55
+ raise "Text not unpacked" if !@iface.text
56
+ @iface.text.save(outname)
39
57
  end
40
58
 
41
59
 
@@ -6,24 +6,58 @@ module Resedit
6
6
 
7
7
  attr_accessor :cfg
8
8
  def initialize(fname, section=nil)
9
- @fname, @section = fname, section
9
+ @fname = fname
10
+ @section = section ? section : []
11
+ @section = [@section] if !@section.is_a?(Array)
10
12
  @cfg = load()
11
- @cfg = (@cfg[@section] or {}) if @section
13
+ @section.each{|s|
14
+ @cfg = (@cfg[s] or {})
15
+ }
12
16
  end
13
17
 
14
18
  def [](nm); @cfg[nm] end
15
19
  def []=(nm, value); @cfg[nm]=value end
20
+ def each(&block);@cfg.each(&block) end
21
+ def length; @cfg.length end
22
+
23
+ def enter(section, createOnAbsent = true)
24
+ section = [section] if !section.is_a?(Array)
25
+ section.each{|s|
26
+ raise "Config section not found #{s} at #{@section}" if !@cfg[s] && !createOnAbsent
27
+ @cfg = @cfg[s] or {}
28
+ @section += [s]
29
+ }
30
+ end
31
+
32
+ def enterOnFile(path)
33
+ ret = nil
34
+ ent = ''
35
+ @cfg.each{|k, _|
36
+ fn = File.join(path, k)
37
+ ret = fn if File.exists?(fn)
38
+ ent = k if ret
39
+ break if ret
40
+ }
41
+ raise "Config not found for files at #{path}" if !ret
42
+ enter(ent, false)
43
+ return ret
44
+ end
16
45
 
17
46
  def load();
18
47
  File.exists?(@fname) ? JSON.parse(File.read(@fname)) : {}
19
48
  end
20
49
 
21
50
  def save()
22
- if @section
51
+ if @section.length>0
23
52
  c = load()
24
- c[@section] = @cfg
53
+ cur = c
54
+ @section[0..-2].each{|s|
55
+ cur[s] = {} if !cur[s]
56
+ cur = cur[s]
57
+ }
58
+ cur[@section[-1]]=@cfg
25
59
  else
26
- c = cfg
60
+ c = @cfg
27
61
  end
28
62
  open(@fname, "w"){|f|
29
63
  f.write(JSON.pretty_generate(c))
@@ -83,6 +83,8 @@ module Resedit
83
83
  t = t[1..-1] while t.length > 0 && (t[0]<'0' || t[0]>'9')
84
84
  tp[1] = t.to_i
85
85
  end
86
+ return str if tp[0] == "s"
87
+ return str+"\x00" if tp[0] == "z"
86
88
  if tp[0]=='f' || (File.exists?(str) && !tp[0])
87
89
  return File.read(str)
88
90
  end
@@ -91,10 +93,10 @@ module Resedit
91
93
  res = eval(str, binding()) if !res
92
94
  return res if res.is_a?(String)
93
95
  res = valueHex(res.to_s(16), tp)
94
- raise str if !res
96
+ raise str if res==nil
95
97
  return res
96
- rescue Exception => e
97
- raise "Bad value: "+e.to_s
98
+ #rescue Exception => e
99
+ # raise "Bad value: "+e.to_s
98
100
  end
99
101
 
100
102
  end
@@ -25,6 +25,7 @@ module Resedit
25
25
  raise "Not EXE file" if fsize < self.class::HSIZE
26
26
  @exe = exe
27
27
  super(file, self.class::HSIZE)
28
+ @hdrtbl = nil
28
29
  @_infoOrig = loadInfo()
29
30
  @_info = nil
30
31
  @info = @_infoOrig
@@ -47,7 +48,7 @@ module Resedit
47
48
 
48
49
  def change(ofs, bytes)
49
50
  super(ofs, bytes)
50
- @_info = nil if (ofs < HSIZE)
51
+ @_info = nil if (ofs < self.class::HSIZE)
51
52
  end
52
53
 
53
54
 
@@ -56,16 +57,50 @@ module Resedit
56
57
  ret = self.class::HDRDESCR.map.with_index { |x, i| [x, v[i]] }.to_h
57
58
  return ret
58
59
  end
60
+
59
61
  def loadTables(file); end
60
62
  def loadTail(file);
61
63
  addData(file, headerSize() - self.class::HSIZE)
62
64
  end
63
65
 
66
+ def _headerTable()
67
+ return @hdrtbl if @hdrtbl
68
+ @hdrtbl = []
69
+ sz = ["acC","vnsS","VNlL","qQ"]
70
+ ofs = 0
71
+ len = self.class::HDRDESCR.length
72
+ self.class::HDRUNPACK.scan(/[a-zA-Z][\d*]*/).each{|s|
73
+ size = sz.index{|v| v.include?(s[0])}
74
+ raise "Unsupported header descr #{s}" if size==nil
75
+ size = 1 << size
76
+ cnt = s.length>1 && s[1]!='*' ? s[1..-1].to_i : 1
77
+ if s[0]=='a'
78
+ cnt = self.class::HSIZE - ofs if s[1]=='*'
79
+ @hdrtbl += [[ofs, cnt, s]]
80
+ ofs += cnt
81
+ next
82
+ end
83
+ cnt = len - @hdrtbl.length if s[1]=='*'
84
+ cnt.times{
85
+ @hdrtbl += [[ofs, size, s[0]]]
86
+ ofs += size
87
+ }
88
+ }
89
+ raise "Header descr unmatch #{@hdrtbl} #{self.class::HDRDESCR}" if @hdrtbl.length!=len
90
+ return @hdrtbl
91
+ end
92
+
93
+ def fieldOffset(field); return _headerTable()[self.class::HDRDESCR.index(field)][0] end
94
+ def fieldSize(field); return _headerTable()[self.class::HDRDESCR.index(field)][1] end
64
95
 
65
- def setInfo(field, values, pack="v*")
96
+ def setInfo(field, values)
66
97
  raise "Unknown header field #{field}" if !self.class::HDRDESCR.include?(field)
98
+ tbl = _headerTable()
67
99
  values = [values] if !values.is_a?(Array)
68
- change(self.class::HDRDESCR.index(field)*2, values.pack(pack))
100
+ ofs = 0
101
+ idx = self.class::HDRDESCR.index(field)
102
+ pack = tbl[idx, values.length].map{|v| v[2]}.join('')
103
+ change(tbl[idx][0], values.pack(pack))
69
104
  end
70
105
 
71
106
  def setBodySize(size); setFileSize(size + headerSize()) end
@@ -73,13 +108,10 @@ module Resedit
73
108
  def headerSize(); self.class::HSIZE end
74
109
 
75
110
  def print(what, how)
76
- return false if what!="header"
111
+ return super(what, how) if what!="header"
77
112
  mode(parseHow(how))
78
- ofs=0
79
- wsz = @exe.wsize
80
113
  @info.each{|k,v|
81
- printf("%20s:\t%s\n", k.to_s, colStr(v, changed?(ofs,wsz)))
82
- ofs+=2
114
+ printf("%20s:\t%s\n", k.to_s, colStr(v, changed?(fieldOffset(k),fieldSize(k))))
83
115
  }
84
116
  puts
85
117
  return true
@@ -89,6 +121,7 @@ module Resedit
89
121
  def fileSize(); raise "NotImplemented" end
90
122
  def setFileSize(size); raise "NotImplemented" end
91
123
  def entry(size); raise "NotImplemented" end
124
+ def addReloc(ofs, value); raise "NotImplemented" end
92
125
  end
93
126
 
94
127
 
@@ -102,12 +135,6 @@ module Resedit
102
135
  @addsz = 0
103
136
  end
104
137
 
105
- def removeAppend()
106
- mode(HOW_CHANGED)
107
- undo(0) if @root.obuf.length==0
108
- @addsz = 0
109
- end
110
-
111
138
  def revert(what)
112
139
  super(what)
113
140
  @addsz = 0
@@ -158,11 +185,33 @@ module Resedit
158
185
  end
159
186
  end
160
187
 
188
+ def textAt(pos, minlen, rexp=nil)
189
+ rexp = /^[[:print:][:space:]]+$/ if !rexp
190
+ sz = size
191
+ ln = [minlen+64, sz-pos].min
192
+ return nil if ln<minlen
193
+ data = getData(pos, ln)
194
+ prev = 0
195
+ while true
196
+ zpos = data.index("\x00")
197
+ return nil if zpos!=nil && zpos<minlen
198
+ data = data[0,zpos] if zpos!=nil
199
+ return nil if (data[prev..-1] =~ rexp) != 0
200
+ return data if zpos != nil
201
+ prev = data.length
202
+ return nil if pos+prev+64 > size
203
+ data += getData(pos+prev, 64)
204
+ end
205
+ end
206
+
207
+ def addrFormatter(hofs); nil end
161
208
  def raw2addr(ofs); raise "Not implemented" end
162
209
  def addr2raw(addr); raise "Not implemented" end
163
210
  def append(bytes, where=nil); raise "NotImplemented" end
164
- def addrFormatter(hofs); nil end
211
+ def removeAppend(); raise "Not Implemented" end
165
212
  def readRelocated(ofs, size); raise "NotImplemented" end
213
+ def findRelocValue(value); raise "NotImplemented" end
214
+ def findStrings(minsize); raise "NotImplemented" end
166
215
  end
167
216
 
168
217
  class ExeFile
@@ -287,8 +336,6 @@ module Resedit
287
336
  log("Change added at %08X", res) if res
288
337
  end
289
338
 
290
- def reloc(ofs); raise "NotImplemented" end
291
-
292
339
  def readRelocated(ofs, size); @body.readRelocated(ofs, size) end
293
340
 
294
341
  def dasm(ofs, size=nil, how=nil)
@@ -298,7 +345,7 @@ module Resedit
298
345
  end
299
346
 
300
347
 
301
- def valueof(str, type)
348
+ def valueof(str, type=nil)
302
349
  puts "value of " + str + " is:"
303
350
  p getValue(str, type).unpack("H*")
304
351
  end
@@ -325,15 +372,48 @@ module Resedit
325
372
  @body.saveData(f)
326
373
  end
327
374
 
328
- def save(filename)
375
+ def save(filename, final=nil)
376
+ raise "Wrong 'final' word" if final and final != 'final'
329
377
  raise "Filename expected." if !filename
330
378
  open(filename, "wb:ascii-8bit"){|f|
331
379
  saveFile(f)
332
380
  }
381
+ return if final
333
382
  open(filename+CFGEXT, "w"){|f|
334
383
  f.write(JSON.pretty_generate(saveConfig()))
335
384
  }
336
385
  end
386
+
387
+ def reloc(ofs, target=nil)
388
+ ofs = s2i(ofs)
389
+ trg = s2i(target) if target
390
+ res = @header.addReloc(ofs, trg)
391
+ log((res ? "Relocation added %08X" : "Relocation %08X already exists"), ofs)
392
+ return res
393
+ end
394
+
395
+ def relocfind(value, type=nil);
396
+ value = getValue(value, type)
397
+ res = @body.findRelocValue(value)
398
+ log("relocs not found") if !res
399
+ return nil if !res
400
+ res.each{|k,v|
401
+ log("found at #{k.to_s(16)} relocs: #{v.map{|a| a.to_s(16)}}")
402
+ }
403
+ return res
404
+ end
405
+
406
+ def stringfind(size=nil)
407
+ size = (size==nil || size=='') ? 3 : s2i(size)
408
+ res = @body.findStrings(size)
409
+ log("strings not found") if !res
410
+ return nil if !res
411
+ log("%d strings found:\n", res.length)
412
+ res.each{|a|
413
+ log("%s at %08X relocs: #{a[2].map{|v| v.to_s(16)}}", a[0], a[1])
414
+ }
415
+ return res
416
+ end
337
417
  end
338
418
 
339
419
  end
data/lib/resedit/mz/bw.rb CHANGED
@@ -9,7 +9,7 @@ module Resedit
9
9
  :RuntimeGdtSize, :MAKEPMVer, :NextHeaderPos, :CVInfoOffset, :LastSelUsed, :PMemAlloc, :AllocIncr, :Reserved4, :Options,
10
10
  :TransStackSel, :ExpFlags, :ProgramSize, :GdtImageSize, :FirstSelector, :DefaultMemStrategy, :Reserved5, :TransferBufferSize,
11
11
  :Reserved6, :ExpPath]
12
- HDRUNPACK = "v14V2v3s6v6HHvs48a64"
12
+ HDRUNPACK = "v14VVv3a6v6CCva48a64"
13
13
 
14
14
  # unsigned_16 signature; /* BW signature to mark valid file */
15
15
  # unsigned_16 last_page_bytes; /* length of image mod 512 */
data/lib/resedit/mz/le.rb CHANGED
@@ -9,63 +9,11 @@ module Resedit
9
9
  :PageSize, :PageShift, :FixupSize, :FixupCsum, :LoaderSize, :LoaderCsum, :ObjectTableOfs, :ObjectsInModule,
10
10
  :ObjectPageOfs, :ObjectIterOfs, :ResourceTableOfs, :ResourceTableEntries, :ResidentTableOfs, :EntryTableOfs,
11
11
  :ModuleDirectivesOfs, :ModuleDirectives, :FixupPageOfs, :FixupRecordOfs, :ImportTblOfs, :ImportEntries, :ImportProcOfs,
12
- :PerPageCsum, :DataPagesOfs, :PreloadPages, :NonResTableOfs, :NonResTableLen, :NonResTableCsum, :AutoDSObject,
12
+ :PerPageCsumOfs, :DataPagesOfs, :PreloadPages, :NonResTableOfs, :NonResTableLen, :NonResTableCsum, :AutoDSObject,
13
13
  :DebugInfoOfs, :DebugInfoLen, :InstancePreload, :InstanceDemand, :Heapsize]
14
- HDRUNPACK = "vHHVvvV40"
15
-
16
- # 00h | "L" "X" |B-ORD|W-ORD| FORMAT LEVEL |
17
- # +-----+-----+-----+-----+-----+-----+-----+-----+
18
- # 08h | CPU TYPE | OS TYPE | MODULE VERSION |
19
- # +-----+-----+-----+-----+-----+-----+-----+-----+
20
- # 10h | MODULE FLAGS | MODULE # OF PAGES |
21
- # +-----+-----+-----+-----+-----+-----+-----+-----+
22
- # 18h | EIP OBJECT # | EIP |
23
- # +-----+-----+-----+-----+-----+-----+-----+-----+
24
- # 20h | ESP OBJECT # | ESP |
25
- # +-----+-----+-----+-----+-----+-----+-----+-----+
26
- # 28h | PAGE SIZE | PAGE OFFSET SHIFT / LE: last page bytes !!! |
27
- # +-----+-----+-----+-----+-----+-----+-----+-----+
28
- # 30h | FIXUP SECTION SIZE | FIXUP SECTION CHECKSUM|
29
- # +-----+-----+-----+-----+-----+-----+-----+-----+
30
- # 38h | LOADER SECTION SIZE |LOADER SECTION CHECKSUM|
31
- # +-----+-----+-----+-----+-----+-----+-----+-----+
32
- # 40h | OBJECT TABLE OFF | # OBJECTS IN MODULE |
33
- # +-----+-----+-----+-----+-----+-----+-----+-----+
34
- # 48h | OBJECT PAGE TABLE OFF | OBJECT ITER PAGES OFF |
35
- # +-----+-----+-----+-----+-----+-----+-----+-----+
36
- # 50h | RESOURCE TABLE OFFSET |#RESOURCE TABLE ENTRIES|
37
- # +-----+-----+-----+-----+-----+-----+-----+-----+
38
- # 58h | RESIDENT NAME TBL OFF | ENTRY TABLE OFFSET |
39
- # +-----+-----+-----+-----+-----+-----+-----+-----+
40
- # 60h | MODULE DIRECTIVES OFF | # MODULE DIRECTIVES |
41
- # +-----+-----+-----+-----+-----+-----+-----+-----+
42
- # 68h | FIXUP PAGE TABLE OFF |FIXUP RECORD TABLE OFF |
43
- # +-----+-----+-----+-----+-----+-----+-----+-----+
44
- # 70h | IMPORT MODULE TBL OFF | # IMPORT MOD ENTRIES |
45
- # +-----+-----+-----+-----+-----+-----+-----+-----+
46
- # 78h | IMPORT PROC TBL OFF | PER-PAGE CHECKSUM OFF |
47
- # +-----+-----+-----+-----+-----+-----+-----+-----+
48
- # 80h | DATA PAGES OFFSET FROM MZ !!! | #PRELOAD PAGES |
49
- # +-----+-----+-----+-----+-----+-----+-----+-----+
50
- # 88h | NON-RES NAME TBL OFF | NON-RES NAME TBL LEN |
51
- # +-----+-----+-----+-----+-----+-----+-----+-----+
52
- # 90h | NON-RES NAME TBL CKSM | AUTO DS OBJECT # |
53
- # +-----+-----+-----+-----+-----+-----+-----+-----+
54
- # 98h | DEBUG INFO OFF | DEBUG INFO LEN |
55
- # +-----+-----+-----+-----+-----+-----+-----+-----+
56
- # A0h | #INSTANCE PRELOAD | #INSTANCE DEMAND |
57
- # +-----+-----+-----+-----+-----+-----+-----+-----+
58
- # A8h | HEAPSIZE |
59
- #
60
-
61
- # Object Table
62
- # +-----+-----+-----+-----+-----+-----+-----+-----+
63
- # 00h | VIRTUAL SIZE | RELOC BASE ADDR |
64
- # +-----+-----+-----+-----+-----+-----+-----+-----+
65
- # 08h | OBJECT FLAGS | PAGE TABLE INDEX |
66
- # +-----+-----+-----+-----+-----+-----+-----+-----+
67
- # 10h | # PAGE TABLE ENTRIES | RESERVED |
68
- # +-----+-----+-----+-----+-----+-----+-----+-----+
14
+ HDRUNPACK = "vCCVvvV*"
15
+ HDR_OFFSETS = [:ObjectTableOfs, :ObjectPageOfs, :ObjectIterOfs, :ResourceTableOfs,:ResidentTableOfs, :EntryTableOfs, :ModuleDirectivesOfs,
16
+ :FixupPageOfs, :FixupRecordOfs, :ImportTblOfs, :ImportProcOfs, :PerPageCsumOfs, :DataPagesOfs, :NonResTableOfs, :DebugInfoOfs]
69
17
 
70
18
  attr_reader :tables
71
19
 
@@ -103,28 +51,6 @@ module Resedit
103
51
  addData(file, headerSize() + @sofs - file.tell())
104
52
  end
105
53
 
106
- def readRelocs()
107
- def read(pos,cnt, unp); [getData(@info[:FixupRecordOfs]+pos, cnt).unpack(unp),pos+cnt] end
108
- ret = {}
109
- pgs = getData(@info[:FixupPageOfs], 4*(@info[:ModulePages]+1)).unpack("V*")
110
- for i in 0..@info[:ModulePages]-1
111
- pos = pgs[i]
112
- op = @tables[:Pages][i]
113
- pgofs = ((op>>16) + ((op>>8) & 0xFF) -1) * @info[:PageSize]
114
- ret[pgofs] = {}
115
- while pos<pgs[i+1]
116
- v,pos = read(pos, 5, "CCvC")
117
- raise "Unknown fixup type #{v[0]} #{v[1]}" if (v[0]!=7 && v[0]!=2) || (v[1] & ~0x10 !=0 )
118
- trg, pos=read(pos, v[1]==0x10 ? 4 : 2,v[1]==0x10 ? "V" : "v")
119
- next if v[2]>0x7FFF
120
- ofs = pgofs+v[2]
121
- ret[pgofs][pgofs+v[2]] = @tables[:Objects][v[3]-1][1]+trg[0]
122
- end
123
- end
124
- return ret
125
- end
126
-
127
-
128
54
  def mode(how)
129
55
  super(how)
130
56
  if @mode == HOW_ORIGINAL
@@ -135,11 +61,143 @@ module Resedit
135
61
  end
136
62
  end
137
63
 
138
- def headerSize(); @info[:DataPagesOfs]-@exe.mzSize end
139
64
 
65
+ def headerSize(); @info[:DataPagesOfs]-@exe.mzSize end
140
66
  def fileSize(); headerSize()+(@info[:ModulePages]-1)*@info[:PageSize]+@info[:PageShift] end
141
67
  def entry; sprintf("0x%08X", @info[:EIP]) end
142
68
 
69
+ def pageRelocs(pageId, fixOfs=nil, fixObj=nil, fixVal=nil)
70
+ def read(pos,cnt, unp); [getData(@info[:FixupRecordOfs]+pos, cnt).unpack(unp), pos+cnt] end
71
+ pgs = getData(@info[:FixupPageOfs]+4*pageId, 8).unpack("V*")
72
+ pgofs = pageId * @info[:PageSize]
73
+ ret = {}
74
+ pos = pgs[0]
75
+ while pos<pgs[1]
76
+ v,pos = read(pos, 5, "CCs<C")
77
+ raise "Unknown fixup type #{v[0]} #{v[1]}" if (v[0]!=7 && v[0]!=2) || (v[1] & ~0x10 !=0 )
78
+ trg, pos=read(pos, v[1]==0x10 ? 4 : 2,v[1]==0x10 ? "V" : "v")
79
+ next if fixOfs!=nil && (v[2]!=fixOfs || (v[1]==0 && fixVal>0xFF))
80
+ if fixOfs
81
+ buf = [fixObj, fixVal].pack("C" + v[1]==0x10 ? "V" : "v")
82
+ change(@info[:FixupRecordOfs]+pos-1, buf) #change fixup object & value
83
+ return true
84
+ end
85
+ next if v[2]<0
86
+ ret[pgofs+v[2]] = @tables[:Objects][v[3]-1][1]+trg[0]
87
+ end
88
+ return false if fixOfs
89
+ return ret
90
+ end
91
+
92
+
93
+ def addPageReloc(pageId, ofs, obj, val)
94
+ return true if pageRelocs(pageId, ofs, obj, val)
95
+ #extend page fixups
96
+ buf = [7, 0x10, ofs, obj, val].pack("CCs<CV")
97
+ #change fixups offsets
98
+ pgs = getData(@info[:FixupPageOfs]+4*(pageId+1), (@info[:ModulePages]-pageId)*4).unpack("V*")
99
+ d = buf.length
100
+ insert(@info[:FixupRecordOfs]+pgs[0], buf)
101
+ pgs = pgs.map{|v| v+d} #fixup sizes change
102
+ change(@info[:FixupPageOfs]+4*(pageId+1), pgs.pack("V*"))
103
+ #fix header
104
+ fixOffsets(@info[:FixupRecordOfs], d)
105
+ @info[:FixupSize]+=d
106
+ setInfo(:FixupSize, @info[:FixupSize])
107
+ @info[:LoaderSize]+=d
108
+ setInfo(:LoaderSize, @info[:LoaderSize])
109
+ @_tables = nil
110
+ mode(HOW_CHANGED)
111
+ rels = pageRelocs(pageId)
112
+ end
113
+
114
+
115
+ def readRelocs()
116
+ ret = {}
117
+ for i in 0..@info[:ModulePages]-1
118
+ pgofs = i * @info[:PageSize]
119
+ ret[pgofs] = pageRelocs(i)
120
+ end
121
+ return ret
122
+ end
123
+
124
+
125
+ def fixOffsets(after, val)
126
+ HDR_OFFSETS.each{|ofs|
127
+ next if @info[ofs]==0 or @info[ofs]<=after
128
+ @info[ofs]+=val
129
+ setInfo(ofs, @info[ofs])
130
+ }
131
+ end
132
+
133
+
134
+ def addSegment(size)
135
+ mode(HOW_CHANGED)
136
+ psz = @info[:PageSize]
137
+ tail = size % psz
138
+ pgs = size / psz + (tail==0 ? 0 : 1)
139
+ tail = psz if tail==0
140
+
141
+ #add new object
142
+ last = @tables[:Objects][-1]
143
+ virt = last[1]+last[0] #lastobject virt base+size
144
+ virt = (virt+psz-1) & ~(psz-1) #align vbase to page size
145
+ obj = [psz*pgs, virt, 0x2047, last[3]+last[4], pgs, 0].pack("V*") # 32b rwx preloaded object
146
+ insert(@info[:ObjectTableOfs] + 0x18*@info[:ObjectsInModule], obj)
147
+ fixOffsets(@info[:ObjectTableOfs], 0x18)
148
+ setInfo(:ObjectsInModule, @info[:ObjectsInModule]+1)
149
+
150
+ #add pages info
151
+ pinfo = ''
152
+ pgs.times{|i|
153
+ pid = @info[:ModulePages]+i+1
154
+ pinfo+=[(pid*@info[:PageSize])<<4].pack("V")
155
+ }
156
+ insert(@info[:ObjectPageOfs]+@info[:ModulePages]*4, pinfo)
157
+ fixOffsets(@info[:ObjectPageOfs], pinfo.length)
158
+
159
+ #add empty fixups
160
+ fixofs = 4*@info[:ModulePages]
161
+ fixval = getData(@info[:FixupPageOfs]+fixofs, 4).unpack("V")[0]
162
+ pinfo = [fixval].pack("V") * pgs #end of fixup table <added pages> times
163
+ insert(@info[:FixupPageOfs]+fixofs+4, pinfo)
164
+ fixOffsets(@info[:FixupPageOfs], pinfo.length)
165
+ setInfo(:FixupSize, @info[:FixupSize]+pinfo.length)
166
+
167
+ #change pages and tail, fix loader size
168
+ setInfo(:ModulePages, @info[:ModulePages]+pgs)
169
+ setInfo(:PageShift, tail)
170
+ setInfo(:LoaderSize, @info[:ImportTblOfs]-@info[:ObjectTableOfs]+1)
171
+
172
+ @_tables = nil
173
+ #reload tables
174
+ mode(HOW_CHANGED)
175
+
176
+ return (@info[:ModulePages]-pgs)*@info[:PageSize]
177
+ end
178
+
179
+
180
+ def addReloc(ofs, trg=nil)
181
+ mode(HOW_CHANGED)
182
+ trg = trg ? @exe.body.raw2addr(trg) : getData(ofs, 4)
183
+ obj = val = -1
184
+ @tables[:Objects].each_with_index{|o,i|
185
+ obj,val = [i+1,trg-o[1]] if o[1]<=trg && o[0]+o[1]>trg
186
+ }
187
+ raise "Target not found for offset: #{trg.to_i(trg)}" if obj==-1
188
+ psz = @info[:PageSize]
189
+ pgid = ofs / psz
190
+ #puts "Adding reloc #{ofs.to_s(16)} -> #{trg.to_s(16)} #{obj}:#{val.to_s(16)} #{pgid}"
191
+ ofs = ofs % psz
192
+ addPageReloc(pgid, ofs, obj, val)
193
+ addPageReloc(pgid+1, ofs-psz, obj, val) if ofs+4>psz
194
+ @_tables = nil
195
+ mode(HOW_CHANGED)
196
+ @exe.body.clearRelocs()
197
+ return true
198
+ end
199
+
200
+
143
201
  def print(what, how=nil)
144
202
  ret = super(what, how)
145
203
  if what=="tables"
@@ -172,6 +230,8 @@ module Resedit
172
230
  @sex
173
231
  end
174
232
 
233
+ def clearRelocs; @relocs=nil end
234
+
175
235
  def relocations()
176
236
  if !@relocs
177
237
  @relocs = @exe.header.readRelocs().sort_by{|k,v| k}.reverse.to_h
@@ -192,8 +252,9 @@ module Resedit
192
252
  return s[0]+ofs-s[1]
193
253
  end
194
254
 
195
- def addr2raw(addr)
255
+ def addr2raw(addr, raiseOnError=true)
196
256
  s = sections.find{|s| s[0]<=addr && s[0]+s[2]>addr}
257
+ return nil if !s && !raiseOnError
197
258
  raise "Not virtual address #{addr.to_s(16)}" if !s
198
259
  return s[1]+addr-s[0]
199
260
  end
@@ -214,6 +275,66 @@ module Resedit
214
275
  return d[0,size]
215
276
  end
216
277
 
278
+ def append(bytes, where=nil)
279
+ @relocs = nil
280
+ mode(HOW_CHANGED)
281
+ pos = @exe.header.addSegment(bytes.length)
282
+ sz = size
283
+ insert(sz, "\x00"*(pos-sz))
284
+ insert(pos, bytes)
285
+ return [raw2addr(pos), pos]
286
+ end
287
+
288
+ def findRelocValue(value)
289
+ rel = relocations()
290
+ cnt = rel.length
291
+ ret={}
292
+ vlen = value.length
293
+ i = 1
294
+ fsz = size
295
+ rel.each{|o,r|
296
+ r.each{|k,v|
297
+ raw = addr2raw(v, false)
298
+ next if raw==nil || raw+vlen>fsz
299
+ vl = getData(raw, vlen)
300
+ next if vl!=value
301
+ ret[v] = [] if !ret[v]
302
+ ret[v] += [raw2addr(k)]
303
+ }
304
+ }
305
+ return nil if ret.length==0
306
+ return ret
307
+ end
308
+
309
+ def findStrings(minsize)
310
+ rel = relocations()
311
+ cnt = rel.length
312
+ fsz = size
313
+ proced = {}
314
+ i = 1
315
+ ret = []
316
+ rel.each{|o,r|
317
+ r.each{|k,v|
318
+ if proced[v]!=nil
319
+ ret[proced[v]][2]+=[raw2addr(k)] if proced[v]>=0
320
+ next
321
+ end
322
+ raw = addr2raw(v, false)
323
+ if raw==nil || raw+minsize>fsz
324
+ proced[v] = -1
325
+ next
326
+ end
327
+ txt = textAt(raw, minsize)
328
+ if txt != nil
329
+ ret+= [[txt, v, [raw2addr(k)]]]
330
+ end
331
+ proced[v] = txt==nil ? -1 : ret.length-1
332
+ }
333
+ }
334
+ return nil if ret.length==0
335
+ return ret
336
+ end
337
+
217
338
  end
218
339
 
219
340
 
@@ -39,6 +39,18 @@ module Resedit
39
39
  }
40
40
  end
41
41
 
42
+ def dump(out, parts, how=nil)
43
+ prts = eval(parts)
44
+ open(out,"wb"){|f|
45
+ prts.each{|i|
46
+ pr = @parts[i]
47
+ pr.header.mode(pr.header.parseHow(how))
48
+ pr.body.mode(pr.header.parseHow(how))
49
+ pr.saveFile(f)
50
+ }
51
+ }
52
+ end
53
+
42
54
  def header; @cur.header end
43
55
  def body; @cur.body end
44
56
  def env; @cur.env end
@@ -62,7 +74,9 @@ module Resedit
62
74
  def append(value, type=nil, where=nil); @cur.append(value, type, where) end
63
75
  def replace(value, type=nil, where=nil); @cur.replace(value, type, where) end
64
76
  def change(ofs, value, disp=nil, type=nil); @cur.change(ofs, value, disp, type) end
65
- def reloc(ofs); @cur.reloc(ofs) end
77
+ def reloc(ofs, target=nil); @cur.reloc(ofs, target) end
78
+ def relocfind(value, type=nil); @cur.relocfind(value, type) end
79
+ def stringfind(size=nil); @cur.stringfind(size) end
66
80
  def dasm(ofs, size=nil, how=nil) @cur.dasm(ofs, size, how) end
67
81
  def valueof(str, type); @cur.valueof(str, type) end
68
82
  def revert(what); @cur.revert(what) end
data/lib/resedit/mz/mz.rb CHANGED
@@ -104,7 +104,7 @@ module Resedit
104
104
  mode(HOW_CHANGED)
105
105
  end
106
106
 
107
- def addReloc(ofs)
107
+ def addReloc(ofs, trg)
108
108
  mode(HOW_CHANGED)
109
109
  #check relocation exists
110
110
  for i in 0..@info[:NumberOfRelocations]-1
@@ -250,6 +250,13 @@ module Resedit
250
250
  return res
251
251
  end
252
252
 
253
+ def removeAppend()
254
+ mode(HOW_CHANGED)
255
+ undo(0) if @root.obuf.length==0
256
+ @addsz = 0
257
+ end
258
+
259
+
253
260
 
254
261
  def print(what, how)
255
262
  if what=="header"
@@ -272,13 +279,6 @@ module Resedit
272
279
  class MZ < ExeFile
273
280
  HDRCLASS = MZHeader
274
281
  BODYCLASS = MZBody
275
-
276
- def reloc(ofs)
277
- ofs = s2i(ofs)
278
- res = @header.addReloc(ofs)
279
- log((res ? "Relocation added %08X" : "Relocation %08X already exists"), ofs)
280
- end
281
-
282
282
  end
283
283
 
284
284
  end
@@ -31,7 +31,7 @@ module Resedit
31
31
  inc=1
32
32
  if ntbl[val]
33
33
  ntbl[val].each{|v,b|
34
- next if str.length < pos+v.length+1
34
+ next if str.length < pos+v.length
35
35
  if v==str[pos,v.length]
36
36
  val=b.chr
37
37
  inc=v.length
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resedit
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.8'
4
+ version: 1.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - bjfn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-11 00:00:00.000000000 Z
11
+ date: 2017-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chunky_png