最近工作中遇到一个很扯的事情,乙方因为各种原因不配合修改程序(虽然他们的程序本身其实很差),实际上只需要做很简单的调整即可,因此不得不自己手工来改了。没有源码,则只有反编译了。这个事情的对错先不提,我们只关心技术上的事。朋友们可以作为技术参考,不可做坏事哈!
一、工具
1、dnspy:https://github.com/0xd4d/dnSpy
反编译工具,支持重新编译,能满足大多数.net程序
2、ILSpy:https://github.com/icsharpcode/ILSpy
反编译工具,只读,不支持重新编译,但反编译的代码效果比dnspy好
3、de4dot:https://github.com/0xd4d/de4dot
脱壳程序
二、项目背景
该项目的程序是运行在windows7触摸屏版本下的全屏应用,这些触摸屏部署在各个商圈,项目之初为了维护方便,启用了触屏的软键盘,即Tablet PC组件。但毕竟部署在外面,就会有人利用该键盘直接操作windows了。所以需要我们远程更新程序包,新的程序包会自动判断如果启用了TabletPC组件,就给禁用了,也就是禁用掉软键盘。
三、关键点
通过程序执行dism命令,来禁用TabletPC组件
1、查询组件状态:
dism /online /Get-FeatureInfo /FeatureName:TabletPCOC
2、禁用组件:
dism /online /Disable-Feature /FeatureName:TabletPCOC
3、启用组件:
dism /online /Enable-Feature /FeatureName:TabletPCOC
4、执行的dism的版本需要和系统一致,否则会报错:
无法使用 32 位版本的 DISM 为正在运行的 64 位操作系统服务
因此要求调用dism的程序编译版本也必须保持一致,这一点之前不知道,google了很久才发现
四、步骤
1、脱壳:
de4dot abc.exe
会得到abc-clean.exe
2、用dnspy打开abc-clean.exe
在form_load方法中,点击右键,选择“编辑方法”
实际上可以在这里增加方法,所以我增加了一个handleTablet的方法,并在form_load中调用:
public partial class MainForm : Form
{
private void handleTablet()
{
string fileName = "dism.exe";
string args = "/online /Get-FeatureInfo /FeatureName:TabletPCOC";
ProcessStartInfo processStartInfo = new ProcessStartInfo(fileName);
processStartInfo.Arguments = args;
processStartInfo.CreateNoWindow = true;
processStartInfo.UseShellExecute = false;
processStartInfo.RedirectStandardError = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
Process process = Process.Start(processStartInfo);
//读取get-featueinfo的结果
string output = process.StandardOutput.ReadToEnd();
process.Close();
if (output.LastIndexOf("状态 : 已启用") > 0 || output.LastIndexOf("状态 : 启用") > 0)
{
//准备执行禁用命令
args = "/online /Disable-Feature /FeatureName:TabletPCOC";
ProcessStartInfo processStartInfo2 = new ProcessStartInfo(fileName);
processStartInfo2.Arguments = args;
processStartInfo2.CreateNoWindow = true;
processStartInfo2.UseShellExecute = false;
processStartInfo2.RedirectStandardError = true;
processStartInfo2.RedirectStandardInput = true;
processStartInfo2.RedirectStandardOutput = true;
Process process2 = Process.Start(processStartInfo2);
//这里不读取禁用的结果,因为没能解决其等待用户输入是否立即重启的输入阻塞问题
process2.Close();
//所以在这里直接等待10秒即可
Thread.Sleep(10000);
Process process3 = Process.Start(processStartInfo);
//再查询一下禁用是否成功
output = process3.StandardOutput.ReadToEnd();
process3.Close();
if (output.LastIndexOf("状态 : 已启用") == -1 && output.LastIndexOf("状态 : 启用") == -1)
{
//已经没有 已启用 或 启用挂起 的状态,则认为成功了,重启系统以生效
//System.Reboot();
}
}
}
}
3、点击编译
4、File->保存模块,选择保存路径,并在Cor20选项卡中,去掉“强制32位”,这样就能保存为64位程序,才能正确执行dism