001: /*
002: JSmooth: a VM wrapper toolkit for Windows
003: Copyright (C) 2003 Rodrigo Reyes <reyes@charabia.net>
004:
005: This program is free software; you can redistribute it and/or modify
006: it under the terms of the GNU General Public License as published by
007: the Free Software Foundation; either version 2 of the License, or
008: (at your option) any later version.
009:
010: This program is distributed in the hope that it will be useful,
011: but WITHOUT ANY WARRANTY; without even the implied warranty of
012: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: GNU General Public License for more details.
014:
015: You should have received a copy of the GNU General Public License
016: along with this program; if not, write to the Free Software
017: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
018:
019: */
020:
021: /*
022: * PEFile.java
023: *
024: * Created on 28 juillet 2003, 21:28
025: */
026:
027: package net.charabia.jsmoothgen.pe;
028:
029: import net.charabia.jsmoothgen.pe.res.*;
030: import java.util.*;
031: import java.io.*;
032: import java.nio.*;
033: import java.nio.channels.*;
034:
035: /**
036: *
037: * @author Rodrigo
038: */
039: public class PEFile {
040: private File m_file;
041: private FileInputStream m_in = null;
042: private FileChannel m_channel = null;
043:
044: private PEOldMSHeader m_oldmsheader;
045: private PEHeader m_header;
046: private Vector m_sections = new Vector();
047:
048: private PEResourceDirectory m_resourceDir;
049:
050: /** Creates a new instance of PEFile */
051: public PEFile(File f) {
052: m_file = f;
053: }
054:
055: public void close() throws IOException {
056: m_in.close();
057: }
058:
059: public void open() throws FileNotFoundException, IOException {
060: m_in = new FileInputStream(m_file);
061: m_channel = m_in.getChannel();
062:
063: m_oldmsheader = new PEOldMSHeader(this );
064:
065: m_oldmsheader.read();
066: // m_oldmsheader.dump(System.out);
067: long headoffset = m_oldmsheader.e_lfanew;
068:
069: m_header = new PEHeader(this , headoffset);
070: m_header.read();
071: // m_header.dump(System.out);
072:
073: int seccount = m_header.NumberOfSections;
074: // System.out.println("LOADING " + seccount + " sections...");
075:
076: long offset = headoffset + (m_header.NumberOfRvaAndSizes * 8)
077: + 24 + 96;
078:
079: for (int i = 0; i < seccount; i++) {
080: // System.out.println("Offset: " + offset + " (" + this.m_channel.position());
081:
082: PESection sect = new PESection(this , offset);
083: sect.read();
084: // sect.dump(System.out);
085: m_sections.add(sect);
086: offset += 40;
087: }
088: // System.out.println("After sections: " + this.m_channel.position() + " (" + offset + ")");
089:
090: ByteBuffer resbuf = null;
091: long resourceoffset = m_header.ResourceDirectory_VA;
092: for (int i = 0; i < seccount; i++) {
093: PESection sect = (PESection) m_sections.get(i);
094: if (sect.VirtualAddress == resourceoffset) {
095: // System.out.println(" Resource section found: " + resourceoffset);
096: PEResourceDirectory prd = new PEResourceDirectory(this ,
097: sect);
098: resbuf = prd.buildResource(sect.VirtualAddress);
099: break;
100: }
101: }
102: }
103:
104: public FileChannel getChannel() {
105: return m_channel;
106: }
107:
108: public static void main(String args[]) throws IOException,
109: CloneNotSupportedException, Exception {
110: //(no)PEFile pe = new PEFile(new File("F:/Program Files/LAN Search PRO/lansearch.exe"));
111:
112: PEFile pe = new PEFile(
113: new File(
114: "F:/Documents and Settings/Rodrigo/Mes documents/projects/jsmooth/skeletons/simplewrap/JWrap.exe"));
115: //PEFile pe = new PEFile(new File("c:/projects/jwrap/Copie.exe"));
116: // PEFile pe = new PEFile(new File("c:/projects/jwrap/test.exe"));
117: // PEFile pe = new PEFile(new File("F:/Program Files/bQuery/bQuery.exe"));
118: // PEFile pe = new PEFile(new File("F:/Program Files/Server Query/query.exe"));
119: // PEFile pe = new PEFile(new File("F:/Program Files/AvRack/rtlrack.exe"));
120: pe.open();
121:
122: // System.out.println("===============\nADDING A RES");
123: File fout = new File(
124: "F:/Documents and Settings/Rodrigo/Mes documents/projects/jsmooth/skeletons/simplewrap/gen-application.jar");
125: FileInputStream fis = new FileInputStream(fout);
126:
127: ByteBuffer data = ByteBuffer.allocate((int) fout.length());
128: data.order(ByteOrder.LITTLE_ENDIAN);
129: FileChannel fischan = fis.getChannel();
130: fischan.read(data);
131: data.position(0);
132: fis.close();
133:
134: PEResourceDirectory resdir = pe.getResourceDirectory();
135: // boolean resb = resdir.replaceResource("JAVA", 103, 1033, data);
136:
137: // String mainclassname = "net.charabia.generation.application.Application";
138: // String mainclassname = "net/charabia/generation/application/Application";
139: // ByteBuffer bcn = ByteBuffer.allocate(mainclassname.length()+1);
140: // for (int i=0; i<mainclassname.length(); i++)
141: // {
142: // bcn.put( (byte) mainclassname.charAt(i));
143: // }
144: // bcn.put((byte)0);
145: // bcn.position(0);
146: // resb = resdir.replaceResource("JAVA", 102, 1033, bcn);
147:
148: // PEResourceDirectory.DataEntry entry = resdir.getData("#14", "A", "#1033");
149: // entry.Data.position(0);
150: // System.out.println("DataEntry found : " + entry + " (size=" + entry.Data.remaining() + ")");
151: // entry.Data.position(0);
152: //
153: // ResIconDir rid = new ResIconDir(entry.Data);
154: // System.out.println("ResIconDir :");
155: // System.out.println(rid.toString());
156: // int iconid = rid.getEntries()[0].dwImageOffset;
157: // System.out.println("Icon Index: " + iconid);
158: //
159: // PEResourceDirectory.DataEntry iconentry = resdir.getData("#3", "#"+iconid, "#1033");
160: // iconentry.Data.position(0);
161: // ResIcon icon = new ResIcon(iconentry.Data);
162: // System.out.println("Icon :");
163: // System.out.println(icon.toString());
164:
165: //java.awt.Image img = java.awt.Toolkit.getDefaultToolkit().getImage ("c:\\test.gif");
166: // java.awt.Image img = java.awt.Toolkit.getDefaultToolkit().getImage ("c:\\gnome-day2.png");
167: java.awt.Image img = java.awt.Toolkit.getDefaultToolkit()
168: .getImage("c:\\gnome-color-browser2.png");
169:
170: java.awt.MediaTracker mt = new java.awt.MediaTracker(
171: new javax.swing.JLabel("toto"));
172: mt.addImage(img, 1);
173: try {
174: mt.waitForAll();
175: } catch (Exception exc) {
176: exc.printStackTrace();
177: }
178:
179: ResIcon newicon = new ResIcon(img);
180:
181: pe.replaceDefaultIcon(newicon);
182:
183: // System.out.println("-----------------\nNEW ICON:");
184: // System.out.println(newicon.toString());
185: //
186: // rid.getEntries()[0].bWidth = (short)newicon.Width;
187: // rid.getEntries()[0].bHeight = (short)(newicon.Height/2);
188: // rid.getEntries()[0].bColorCount = (short)(1 <<newicon.BitsPerPixel);
189: // rid.getEntries()[0].wBitCount = newicon.BitsPerPixel;
190: // rid.getEntries()[0].dwBytesInRes = newicon.getData().remaining();
191: //
192: // iconentry.Data = newicon.getData();
193: // iconentry.Size = iconentry.Data.remaining();
194: //
195: // entry.setData(rid.getData());
196: // System.out.println("POST CHANGE ResIconDir :");
197: // System.out.println(rid.toString());
198:
199: // ResIcon test = new ResIcon(icon.getData());
200: // System.out.println("PROOF-TEST:\n" + test.toString());
201:
202: /// BACK
203: //
204: // rid.getEntries()[0].bWidth = (short)icon.Width;
205: // rid.getEntries()[0].bHeight = (short)(icon.Height/2);
206: // rid.getEntries()[0].bColorCount = (short)(1 <<icon.BitsPerPixel);
207: // rid.getEntries()[0].wBitCount = icon.BitsPerPixel;
208: // iconentry.Data = icon.getData();
209: // iconentry.Size = iconentry.Data.remaining();
210:
211: // resdir.addNewResource("POUET", "A666", "#1033", data);
212:
213: //resdir.dump(System.out);
214:
215: // System.out.println("New size = " + resdir.size());
216: File out = new File(
217: "F:/Documents and Settings/Rodrigo/Mes documents/projects/jsmooth/skeletons/simplewrap/COPIE.exe");
218: pe.dumpTo(out);
219:
220: }
221:
222: public PEResourceDirectory getResourceDirectory()
223: throws IOException {
224: if (m_resourceDir != null)
225: return m_resourceDir;
226:
227: long resourceoffset = m_header.ResourceDirectory_VA;
228: for (int i = 0; i < m_sections.size(); i++) {
229: PESection sect = (PESection) m_sections.get(i);
230: if (sect.VirtualAddress == resourceoffset) {
231: m_resourceDir = new PEResourceDirectory(this , sect);
232: return m_resourceDir;
233: }
234: }
235:
236: return null;
237: }
238:
239: public void dumpTo(File destination) throws IOException,
240: CloneNotSupportedException {
241: int outputcount = 0;
242: FileOutputStream fos = new FileOutputStream(destination);
243: FileChannel out = fos.getChannel();
244:
245: //
246: // Make a copy of the Header, for safe modifications
247: //
248: PEOldMSHeader oldmsheader = (PEOldMSHeader) this .m_oldmsheader
249: .clone();
250: PEHeader peheader = (PEHeader) m_header.clone();
251: Vector sections = new Vector();
252: for (int i = 0; i < m_sections.size(); i++) {
253: PESection sect = (PESection) m_sections.get(i);
254: PESection cs = (PESection) sect.clone();
255: sections.add(cs);
256: }
257:
258: //
259: // First, write the old MS Header, the one starting
260: // with "MZ"...
261: //
262: long newexeoffset = oldmsheader.e_lfanew;
263: ByteBuffer msheadbuffer = oldmsheader.get();
264: outputcount = out.write(msheadbuffer);
265: this .m_channel.position(64);
266: out.transferFrom(this .m_channel, 64, newexeoffset - 64);
267:
268: //
269: // Then Write the new Header...
270: //
271: ByteBuffer headbuffer = peheader.get();
272: out.position(newexeoffset);
273: outputcount = out.write(headbuffer);
274:
275: //
276: // After the header, there are all the section
277: // headers...
278: //
279: long offset = oldmsheader.e_lfanew
280: + (m_header.NumberOfRvaAndSizes * 8) + 24 + 96;
281: out.position(offset);
282: for (int i = 0; i < sections.size(); i++) {
283: // System.out.println(" offset: " + out.position());
284: PESection sect = (PESection) sections.get(i);
285:
286: ByteBuffer buf = sect.get();
287: outputcount = out.write(buf);
288: }
289:
290: //
291: // Now, we write the real data: each of the section
292: // and their data...
293: //
294:
295: // Not sure why it's always at 1024... ?
296: offset = 1024;
297:
298: //
299: // Dump each section data
300: //
301:
302: long virtualAddress = offset;
303: if ((virtualAddress % peheader.SectionAlignment) > 0)
304: virtualAddress += peheader.SectionAlignment
305: - (virtualAddress % peheader.SectionAlignment);
306:
307: long resourceoffset = m_header.ResourceDirectory_VA;
308: for (int i = 0; i < sections.size(); i++) {
309: PESection sect = (PESection) sections.get(i);
310: if (resourceoffset == sect.VirtualAddress) {
311: // System.out.println("Dumping RES section " + i + " at " + offset + " from " + sect.PointerToRawData + " (VA=" + virtualAddress + ")");
312: out.position(offset);
313: long sectoffset = offset;
314: PEResourceDirectory prd = this .getResourceDirectory();
315: ByteBuffer resbuf = prd
316: .buildResource(sect.VirtualAddress);
317: resbuf.position(0);
318:
319: out.write(resbuf);
320: offset += resbuf.capacity();
321: long rem = offset % this .m_header.FileAlignment;
322: if (rem != 0)
323: offset += this .m_header.FileAlignment - rem;
324:
325: if (out.size() + 1 < offset) {
326: ByteBuffer padder = ByteBuffer.allocate(1);
327: out.write(padder, offset - 1);
328: }
329:
330: long virtualSize = resbuf.capacity();
331: if ((virtualSize % peheader.FileAlignment) > 0)
332: virtualSize += peheader.SectionAlignment
333: - (virtualSize % peheader.SectionAlignment);
334:
335: sect.PointerToRawData = sectoffset;
336: sect.SizeOfRawData = resbuf.capacity();
337: if ((sect.SizeOfRawData % this .m_header.FileAlignment) > 0)
338: sect.SizeOfRawData += (this .m_header.FileAlignment - (sect.SizeOfRawData % this .m_header.FileAlignment));
339: sect.VirtualAddress = virtualAddress;
340: sect.VirtualSize = virtualSize;
341:
342: virtualAddress += virtualSize;
343:
344: } else if (sect.PointerToRawData > 0) {
345: // System.out.println("Dumping section " + i + "/" + sect.getName() + " at " + offset + " from " + sect.PointerToRawData + " (VA=" + virtualAddress + ")");
346: out.position(offset);
347: this .m_channel.position(sect.PointerToRawData);
348: long sectoffset = offset;
349:
350: out.position(offset + sect.SizeOfRawData);
351: ByteBuffer padder = ByteBuffer.allocate(1);
352: out.write(padder, offset + sect.SizeOfRawData - 1);
353:
354: long outted = out.transferFrom(this .m_channel, offset,
355: sect.SizeOfRawData);
356: offset += sect.SizeOfRawData;
357: // System.out.println("offset before alignment, " + offset);
358:
359: long rem = offset % this .m_header.FileAlignment;
360: if (rem != 0) {
361: offset += this .m_header.FileAlignment - rem;
362: }
363: // System.out.println("offset after alignment, " + offset);
364:
365: // long virtualSize = sect.SizeOfRawData;
366: // if ((virtualSize % peheader.SectionAlignment)>0)
367: // virtualSize += peheader.SectionAlignment - (virtualSize%peheader.SectionAlignment);
368:
369: sect.PointerToRawData = sectoffset;
370: // sect.SizeOfRawData =
371: sect.VirtualAddress = virtualAddress;
372: // sect.VirtualSize = virtualSize;
373:
374: virtualAddress += sect.VirtualSize;
375: if ((virtualAddress % peheader.SectionAlignment) > 0)
376: virtualAddress += peheader.SectionAlignment
377: - (virtualAddress % peheader.SectionAlignment);
378:
379: } else {
380: // generally a BSS, with a virtual size but no
381: // data in the file...
382: // System.out.println("Dumping section " + i + " at " + offset + " from " + sect.PointerToRawData + " (VA=" + virtualAddress + ")");
383: long virtualSize = sect.VirtualSize;
384: if ((virtualSize % peheader.SectionAlignment) > 0)
385: virtualSize += peheader.SectionAlignment
386: - (virtualSize % peheader.SectionAlignment);
387:
388: sect.VirtualAddress = virtualAddress;
389: // sect.VirtualSize = virtualSize;
390: virtualAddress += virtualSize;
391:
392: }
393: }
394:
395: //
396: // Now that all the sections have been written, we have the
397: // correct VirtualAddress and Sizes, so we can update the new
398: // header and all the section headers...
399:
400: peheader.updateVAAndSize(m_sections, sections);
401: headbuffer = peheader.get();
402: out.position(newexeoffset);
403: outputcount = out.write(headbuffer);
404:
405: // peheader.dump(System.out);
406: /// System.out.println("Dumping the section again...");
407: offset = oldmsheader.e_lfanew
408: + (m_header.NumberOfRvaAndSizes * 8) + 24 + 96;
409: out.position(offset);
410: for (int i = 0; i < sections.size(); i++) {
411: // System.out.println(" offset: " + out.position());
412: PESection sect = (PESection) sections.get(i);
413: // sect.dump(System.out);
414: ByteBuffer buf = sect.get();
415: outputcount = out.write(buf);
416: }
417:
418: fos.flush();
419: fos.close();
420: }
421:
422: /*
423: */
424:
425: public void replaceDefaultIcon(ResIcon icon) throws Exception {
426: PEResourceDirectory resdir = getResourceDirectory();
427:
428: PEResourceDirectory.DataEntry entry = resdir.getData("#14",
429: null, null);
430: if (entry == null) {
431: throw new Exception(
432: "Can't find any icon group in the file!");
433: }
434:
435: entry.Data.position(0);
436: // System.out.println("DataEntry found : " + entry + " (size=" + entry.Data.remaining() + ")");
437: entry.Data.position(0);
438:
439: ResIconDir rid = new ResIconDir(entry.Data);
440: // System.out.println("ResIconDir :");
441: // System.out.println(rid.toString());
442: int iconid = rid.getEntries()[0].dwImageOffset;
443: // System.out.println("Icon Index: " + iconid);
444:
445: PEResourceDirectory.DataEntry iconentry = resdir.getData("#3",
446: "#" + iconid, null);
447: iconentry.Data.position(0);
448: // System.out.println("Icon :");
449: // System.out.println(icon.toString());
450:
451: rid.getEntries()[0].bWidth = (short) icon.Width;
452: rid.getEntries()[0].bHeight = (short) (icon.Height / 2);
453: rid.getEntries()[0].bColorCount = (short) (1 << icon.BitsPerPixel);
454: rid.getEntries()[0].wBitCount = icon.BitsPerPixel;
455: rid.getEntries()[0].dwBytesInRes = icon.getData().remaining();
456:
457: iconentry.Data = icon.getData();
458: iconentry.Size = iconentry.Data.remaining();
459:
460: entry.setData(rid.getData());
461: }
462:
463: }
|