View Javadoc

1   package com.ochafik.lang.jnaerator.nativesupport;
2   
3   import static com.ochafik.lang.jnaerator.nativesupport.dllexport.DbgHelpLibrary.IMAGE_DIRECTORY_ENTRY_EXPORT;
4   import static com.ochafik.lang.jnaerator.nativesupport.dllexport.DbgHelpLibrary.IMAGE_DOS_SIGNATURE;
5   import static com.ochafik.lang.jnaerator.nativesupport.dllexport.DbgHelpLibrary.IMAGE_NT_SIGNATURE;
6   import static com.ochafik.lang.jnaerator.nativesupport.dllexport.DbgHelpLibrary.INSTANCE;
7   import static com.ochafik.lang.jnaerator.nativesupport.dllexport.DbgHelpLibrary.UNDNAME_COMPLETE;
8   
9   import static com.ochafik.lang.jnaerator.nativesupport.NativeExportUtils.*;
10  
11  import java.io.File;
12  import java.io.IOException;
13  import java.io.RandomAccessFile;
14  import java.util.ArrayList;
15  import java.util.List;
16  import java.util.regex.Pattern;
17  
18  import com.ochafik.lang.jnaerator.nativesupport.dllexport.IMAGE_DOS_HEADER;
19  import com.ochafik.lang.jnaerator.nativesupport.dllexport.IMAGE_EXPORT_DIRECTORY;
20  import com.ochafik.lang.jnaerator.nativesupport.dllexport.IMAGE_NT_HEADERS;
21  import com.ochafik.lang.jnaerator.nativesupport.dllexport.IMAGE_SECTION_HEADER;
22  import com.ochafik.util.string.RegexUtils;
23  import com.sun.jna.Memory;
24  import com.sun.jna.Pointer;
25  import com.sun.jna.PointerUtils;
26  
27  public class DllExport {
28  	private static final Pattern libraryFileNamePattern = Pattern.compile("^([^.]+)\\.dll");
29  	public static String createSourceFile(File sourceFile, List<ParsedExport> dllExports) {
30  		if (dllExports == null)
31  			return null;
32  		
33  		StringBuilder b = new StringBuilder();
34  		b.append("#line \"" + sourceFile + "\"\n");
35  		for (ParsedExport ex : dllExports) {
36  			b.append("// @mangling " + ex.mangling + "\n");
37  			b.append(ex.demangled + ";\n");
38  			b.append("\n");
39  		}
40  		return b.toString();
41  	}
42  	public static List<ParsedExport> parseDllExports(File f) throws IOException {
43  		List<ParsedExport> ret = new ArrayList<ParsedExport>();
44  		List<String> list = OutputDllFunctions(f);
45  		if (list == null)
46  			return null;
47  		
48  		String library = RegexUtils.findFirst(f.getName(), libraryFileNamePattern, 1);
49  		
50  		int outSize = 8196;
51  		byte[] bytes = new byte[outSize];
52  		Memory m = new Memory(outSize);
53  		for (String symbol : list) {
54  			INSTANCE.UnDecorateSymbolName(symbol, m.getByteBuffer(0, outSize), outSize, UNDNAME_COMPLETE);
55  			m.read(0, bytes, 0, outSize);	
56  			int len = 0;
57  			while (len < outSize && bytes[len] != 0)
58  				len++;
59  			ParsedExport ex = new ParsedExport();
60  			ex.mangling = symbol;
61  			ex.demangled = new String(bytes, 0, len);
62  			ex.library = library ;
63  			ret.add(ex);
64  		}
65  		return ret;
66  	}
67  	private static List<String> OutputDllFunctions(File f) throws IOException {
68  		RandomAccessFile raf = new RandomAccessFile(f, "r");
69  		IMAGE_DOS_HEADER dosHeader = deserializeStruct(new IMAGE_DOS_HEADER(), raf, 0);
70  		if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE)
71  			return null;
72  		
73  		long ntHeaderBase = dosHeader.e_lfanew.longValue();
74  		IMAGE_NT_HEADERS ntHeader = deserializeStruct(new IMAGE_NT_HEADERS(), raf, ntHeaderBase);
75          if (ntHeader.Signature != IMAGE_NT_SIGNATURE)
76          	return null;
77          
78      	int exportsStartRVA = ntHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
79      	IMAGE_SECTION_HEADER header = GetExportsSectionHeader(raf, exportsStartRVA, ntHeaderBase, ntHeader );
80          if (header == null)
81          	return null;
82  
83          int delta = header.VirtualAddress - header.PointerToRawData;
84          IMAGE_EXPORT_DIRECTORY exportDir = deserializeStruct(new IMAGE_EXPORT_DIRECTORY(), raf, exportsStartRVA - delta);
85          
86          List<String> ret = new ArrayList<String>(exportDir.NumberOfNames);
87  		//IntBuffer functions = ByteBuffer.wrap(GetFileBytes(raf, PointerUtils.getAddress(exportDir.AddressOfFunctions) - delta, exportDir.NumberOfFunctions * 4)).asIntBuffer();
88          //ShortBuffer ordinals = ByteBuffer.wrap(GetFileBytes(raf, PointerUtils.getAddress(exportDir.AddressOfNameOrdinals) - delta, exportDir.NumberOfNames * 2)).asShortBuffer();
89          for (int i = 0; i < exportDir.NumberOfNames; i++ ) {
90              int pstr = readLittleEndianInt(raf, PointerUtils.getAddress(exportDir.AddressOfNames) - delta + i * Pointer.SIZE);
91              String name = new String(GetFileBytes(raf, pstr - delta, -1));
92              ret.add(name);
93          }
94          return ret;
95  	}
96  	private static IMAGE_SECTION_HEADER GetExportsSectionHeader(RandomAccessFile raf, int exportsStartRVA, long ntHeaderBase, IMAGE_NT_HEADERS ntHeader) throws IOException {
97  		IMAGE_SECTION_HEADER firstSection = new IMAGE_SECTION_HEADER();
98  		byte[] bytes = GetFileBytes(
99  			raf, 
100 			ntHeaderBase +
101 			PointerUtils.getAddress(ntHeader.OptionalHeader.getPointer()) - 
102 			PointerUtils.getAddress(ntHeader.getPointer()) + 
103 			ntHeader.FileHeader.SizeOfOptionalHeader,
104 			firstSection.size() * ntHeader.FileHeader.NumberOfSections
105 		);
106 		IMAGE_SECTION_HEADER[] sections = firstSection.toArray(ntHeader.FileHeader.NumberOfSections);
107 		sections[0].getPointer().write(0, bytes, 0, bytes.length);
108 		for (IMAGE_SECTION_HEADER section : sections) {
109 			section.read();
110 			if (exportsStartRVA >= section.VirtualAddress && exportsStartRVA < (section.VirtualAddress + section.Misc.VirtualSize))
111 				return section;
112 		}
113 		return null;
114 	}
115 }