GP-42 Initial implementation of Pdb symbol store / symbol servers

This commit is contained in:
dev747368 2020-07-21 18:34:35 -04:00
parent df72f24b58
commit 425667e640
93 changed files with 7715 additions and 3874 deletions

View file

@ -0,0 +1,88 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.net;
import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Redirect;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.SSLContext;
public class HttpClients {
/**
* Note: java.net.http.HttpClient instances can allocate system resources (file handles),
* and frequently creating a new HttpClient could exhaust system resources.
* <p>
* There is no "close()" on a HttpClient to release resources. The system resources
* allocated by HttpClient instances will be released when the instance is gc'd.
* However, since the resources in question (filehandles) are not tied to memory pressure,
* its possible a gc() won't happen before running out of file handles if a few hundred
* HttpClient instances have been created / discarded.
* <p>
* Also note, there is no per-connection ability to disable hostname verification in a
* SSL/TLS connection. There is a global flag:
* -Djdk.internal.httpclient.disableHostnameVerification
*
*/
private static HttpClient client;
/**
* Creates a HttpClient Builder using Ghidra SSL/TLS context info.
*
* @return a new HttpClient Builder
* @throws IOException if error in PKI settings or crypto configuration
*/
public static HttpClient.Builder newHttpClientBuilder() throws IOException {
if (!ApplicationKeyManagerFactory.initialize()) {
if (ApplicationKeyManagerFactory.getKeyStore() != null) {
throw new IOException("Failed to initialize PKI certificate keystore");
}
}
try {
return HttpClient.newBuilder()
.sslContext(SSLContext.getDefault())
.followRedirects(Redirect.NORMAL);
}
catch (NoSuchAlgorithmException nsae) {
throw new IOException("Missing algorithm", nsae);
}
}
/**
* Returns a shared, plain (no special options) {@link HttpClient}.
*
* @return a {@link HttpClient}
* @throws IOException if error in PKI settings or crypto configuration
*/
public static synchronized HttpClient getHttpClient() throws IOException {
if (client == null) {
client = newHttpClientBuilder().build();
}
return client;
}
/**
* Clears the currently cached {@link HttpClient}, forcing it to be
* rebuilt during the next call to {@link #getHttpClient()}.
*/
public static synchronized void clearHttpClient() {
client = null;
}
}

View file

@ -110,6 +110,10 @@ public class SSLContextInitializer implements ModuleInitializer {
// Establish default HTTPS socket factory
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
// Force the HttpClient to be re-created by the next request to
// HttpClients.getHttpClient() so that the new SSLContext is used
HttpClients.clearHttpClient();
return true;
}

View file

@ -15,39 +15,15 @@
*/
package ghidra.net.http;
import ghidra.net.ApplicationKeyManagerFactory;
import ghidra.util.Msg;
import java.io.*;
import java.net.*;
import java.util.Properties;
import ghidra.net.ApplicationKeyManagerFactory;
import ghidra.util.Msg;
public class HttpUtil {
public static void main(String[] args) {
Properties properties = new Properties();
properties.setProperty("User-Agent", "Microsoft-Symbol-Server/6.3.9600.17298");
String urlStr =
"http://msdl.microsoft.com/download/symbols/write.pdb/4FD8CA6696F445A7B969AB9BBD76E4591/write.pd_";
String homeDir = System.getProperty("user.home");
File f = new File(homeDir + "/Downloads", "write.pdb.deleteme");
try {
getFile(urlStr, properties, true, f);
System.out.println("getFile completed: " + f);
}
catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Execute an HTTP/HTTPS GET request and return the resulting HttpURLConnection.
@ -155,4 +131,5 @@ public class HttpUtil {
return connection.getContentType();
}
}

View file

@ -15,25 +15,23 @@
*/
package ghidra.util.filechooser;
import java.util.*;
import java.util.stream.Collectors;
import java.io.File;
import java.io.FileFilter;
import java.util.Enumeration;
import java.util.Hashtable;
/**
* A convenience implementation of FileFilter that filters out
* all files except for those type extensions that it knows about.
*
* Extensions are of the type ".foo", which is typically found on
* Windows and Unix boxes, but not on Mac. Case is ignored.
*
* <p>
* Extensions are of the type "foo" (no leading dot). Case is ignored.
* <p>
* Example - create a new filter that filters out all files
* but gif and jpg image files:
* <pre>
* GhidraFileChooser chooser = new GhidraFileChooser();
* ExtensionFileFilter filter = new ExtensionFileFilter(
* new String{"gif", "jpg"}, "JPEG and GIF Images")
* chooser.addFileFilter(filter);
* chooser.addFileFilter(ExtensionFilFilter.forExtensions("JPEG and GIF Images", "gif", "jpg"));
*</pre>
*/
public class ExtensionFileFilter implements GhidraFileFilter {
@ -50,19 +48,16 @@ public class ExtensionFileFilter implements GhidraFileFilter {
return eff;
}
private Hashtable<String, ExtensionFileFilter> filters = null;
private String description = null;
private String fullDescription = null;
private boolean useExtensionsInDescription = true;
private List<String> extensions;
private String description;
private String fullDescription;
/**
* Creates a file filter that accepts the given file type.
* Example: new ExtensionFileFilter("jpg", "JPEG Image Images");
* Example: new ExtensionFileFilter("jpg", "JPEG Images");
*
* Note that the "." before the extension is not needed. If
* provided, it will be ignored.
*
* @see #addExtension
* @param extension file extension to match, without leading dot
* @param description descriptive string of the filter
*/
public ExtensionFileFilter(String extension, String description) {
this(new String[] { extension }, description);
@ -72,16 +67,15 @@ public class ExtensionFileFilter implements GhidraFileFilter {
* Creates a file filter from the given string array and description.
* Example: new ExtensionFileFilter(String {"gif", "jpg"}, "Gif and JPG Images");
*
* Note that the "." before the extension is not needed and will be ignored.
*
* @see #addExtension
* @param filters array of file name extensions, each without a leading dot
* @param description descriptive string of the filter
*/
public ExtensionFileFilter(String[] filters, String description) {
this.filters = new Hashtable<String, ExtensionFileFilter>(filters.length);
for (String filter : filters) {
addExtension(filter);//add filters one by one
}
setDescription(description);
this.extensions = Arrays.asList(filters)
.stream()
.map(String::toLowerCase)
.collect(Collectors.toList());
this.description = description;
}
/**
@ -90,7 +84,6 @@ public class ExtensionFileFilter implements GhidraFileFilter {
*
* Files that begin with "." are ignored.
*
* @see #getExtension
* @see FileFilter#accept
*/
@Override
@ -101,133 +94,37 @@ public class ExtensionFileFilter implements GhidraFileFilter {
if (model.isDirectory(f)) {
return true;
}
if (filters.size() == 0) {
if (extensions.isEmpty()) {
return true;
}
String extension = getExtension(f);
return extension != null && filters.get(extension) != null;
}
/**
* Return the extension portion of the file's name .
*
* @see #getExtension
* @see FileFilter#accept
*/
public String getExtension(File f) {
if (f != null) {
String filename = f.getName();
int i = filename.lastIndexOf('.');
if (i > 0 && i < filename.length() - 1) {
return filename.substring(i + 1).toLowerCase();
String filename = f.getName().toLowerCase();
if (filename.startsWith(".")) {
return false;
}
int fnLen = filename.length();
for (String ext : extensions) {
int extLen = ext.length();
int extStart = fnLen - extLen;
if (extStart > 0 && filename.substring(extStart).equals(ext) &&
filename.charAt(extStart - 1) == '.') {
return true;
}
}
return null;
return false;
}
/**
* Adds a filetype "dot" extension to filter against.
*
* For example: the following code will create a filter that filters
* out all files except those that end in ".jpg" and ".tif":
*
* ExtensionFileFilter filter = new ExtensionFileFilter();
* filter.addExtension("jpg");
* filter.addExtension("tif");
*
* Note that the "." before the extension is not needed and will be ignored.
*/
public void addExtension(String extension) {
if (filters == null) {
filters = new Hashtable<String, ExtensionFileFilter>(5);
}
filters.put(extension.toLowerCase(), this);
fullDescription = null;
}
/**
* Returns the human readable description of this filter. For
* example: "JPEG and GIF Image Files (*.jpg, *.gif)"
*/
@Override
public String getDescription() {
if (fullDescription == null) {
fullDescription = "";
if (description == null || isExtensionListInDescription()) {
if (description != null) {
fullDescription = description;
}
fullDescription += " (";
// build the description from the extension list
fullDescription = Objects.requireNonNullElse(description, "");
if (filters.size() == 0) {
fullDescription += "*.*";
}
else {
boolean firstExt = true;
Enumeration<String> extensions = filters.keys();
if (extensions != null) {
while (extensions.hasMoreElements()) {
if (!firstExt) {
fullDescription += ",";
}
else {
firstExt = false;
}
fullDescription += "*." + extensions.nextElement();
}
}
}
fullDescription += ")";
}
else {
fullDescription = description;
}
// add prettified extensions to the description string
fullDescription += " (";
fullDescription += extensions.isEmpty()
? "*.*"
: extensions.stream().map(s -> "*." + s).collect(Collectors.joining(","));
fullDescription += ")";
}
return fullDescription;
}
/**
* Sets the human readable description of this filter. For
* example: filter.setDescription("Gif and JPG Images");
*
* @see #setDescription
* @see #setExtensionListInDescription
* @see #isExtensionListInDescription
*/
public void setDescription(String description) {
this.description = description;
fullDescription = null;
}
/**
* Determines whether the extension list (.jpg, .gif, etc) should
* show up in the human readable description.
*
* Only relevant if a description was provided in the constructor
* or using setDescription();
*
* @see #getDescription
* @see #setDescription
* @see #isExtensionListInDescription
*/
public void setExtensionListInDescription(boolean b) {
useExtensionsInDescription = b;
fullDescription = null;
}
/**
* Returns whether the extension list (.jpg, .gif, etc) should
* show up in the human readable description.
*
* Only relevant if a description was provided in the constructor
* or using setDescription();
*
* @see #getDescription
* @see #setDescription
* @see #setExtensionListInDescription
*/
public final boolean isExtensionListInDescription() {
return useExtensionsInDescription;
}
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,12 +15,16 @@
*/
package ghidra.util.task;
/**
* Similar to a {@link Runnable} except the {@link #monitoredRun(TaskMonitor) run}
* method is given a monitor to report progress and check for cancellation.
*/
public interface MonitoredRunnable {
/**
* Similar to a runnable except that is given a monitor to report progress and check for
* cancellation.
* @param monitor the TaskMonitor to use.
*/
public void monitoredRun(TaskMonitor monitor);
* Similar to a runnable except the run method is given a monitor
* to report progress and check for cancellation.
* @param monitor the TaskMonitor to use.
*/
void monitoredRun(TaskMonitor monitor);
}

View file

@ -0,0 +1,48 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.net.http;
import java.util.Properties;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
public class HttpUtilTest {
public static void main(String[] args) {
Properties properties = new Properties();
properties.setProperty("User-Agent", "Microsoft-Symbol-Server/6.3.9600.17298");
String urlStr =
"http://msdl.microsoft.com/download/symbols/write.pdb/4FD8CA6696F445A7B969AB9BBD76E4591/write.pd_";
String homeDir = System.getProperty("user.home");
File f = new File(homeDir + "/Downloads", "write.pdb.deleteme");
try {
HttpUtil.getFile(urlStr, properties, true, f);
System.out.println("getFile completed: " + f);
}
catch (MalformedURLException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}