记录一次修复AMDAutoUpdate不正常工作的流程

起因

最近从i5-7500更换到5700x,虽然虚拟机开爽了,但是自从为了完全掌握CUP信息(也为了将来可能会去接触的CPU超频)手贱下载了AMD Ryzen Master以后,我发现每过一段时间都会有个名为“AMDAutoUpdate”的进程弹框并卡住。为了彻底把这个恼人的弹框干掉,我开始寻找它卡住的根源。

AMDAutoUpdate弹框
卡住的AMDAutoUpdate

先说结论

原因是AMD在更新程序的配置文件中使用了旧域名www2.ati.com作为软件的下载源。当自动重定向至drivers.amd.com时,更新程序没有处理302状态码,同时也没有设置AcceptAccept-EncodingAccept-Language以及User-Agent标头,导致下载到了空文件,最终使得更新失败。
我目前使用的解决方案是修改名为AMDAutoUpdate.exe.config的配置文件,将VersionInfo请求的服务器导航到自行编写的本地程序上,让这个程序代理更新程序访问www2.ati.com的请求。

编写的程序在此 - FkAMDAutoUpdater

具体分析

进入程序目录C:\Program Files\AMD\AutoUpdate,可以看到仅有imagespackages两个文件夹以及AMDAutoUpdate.exeAMDAutoUpdate.exe.configAMDAutoUpdate.logAutoUpdateTaskInterval.vbsVersionInfo.xml五个文件。根据“有日志先看日志”的准则,直接打开AMDAutoUpdate.log进行查看。

AMDAutoUpdate程序文件
AMDAutoUpdate程序目录,可以发现文件结构非常简单

打开日志文件后,可以看到数次程序启动记录,以及紧跟着程序启动后的“缺少根元素。”报错。根据报错信息,判断程序可能是出现了XML解析异常。但出现这种异常的话,要么是XML文件损坏,要么是程序在编写时就有问题。而这两种问题无论是哪一种都非常棘手——因为无论是XML文件还是程序本身,其中的细节只有作为下发者的AMD才知道,作为用户的我很难有办法对它们进行处理。不过,我已经受够了时不时弹出黑框的AMDAutoUpdate。

程序启动记录以及报错信息
删除日志文件后为了补录而重新引发了异常,不过具体信息与首次打开时一致

回溯日志文件,可以发现“缺少根元素。”这是一句中文报错,这意味这这个程序很有可能是基于.NET Framework所构建的,甚至编写它的程序员可能还是用的是C#。于是我立马拉出ILSpy尝试对它进行反编译——
成功反编译AMDAutoUpdate

事实证明,我的猜想是正确的,ILSpy成功反编译了AMDAutoUpdate。根据之前日志中的信息,我用“XML”作为关键字在程序的各个类里搜索,最后在MainWindow以及UpdateWindowDialog两个类中,我找到了System.Xml的引用。

MainWindow引用System.Xml UpdateWindowDialog引用System.Xml

但到此时,具体是何处在报错我仍然不得而知。不过,分析MainWindow以及UpdateWindowDialog类型的继承关系可以发现,这个程序是基于WPF进行UI呈现的。再结合类型名称分析,那么MainWindow就应该是这个程序呈现的第一个窗口,而我也应该从MainWindow开始缕清整个程序的运行逻辑。最后在WPF程序的Application_Startup事件处理中我也证实了我的猜想:

	[STAThread]
	private void Application_Startup(object sender, StartupEventArgs e)
	{
		// ...省略参数检测代码 //
		if (!createdNew)
		{
			// ...省略检测是否存在已启动的相同程序代码 //
			if (!exitFlag)
			{
				mutexOwned = true;
				CLog.Initialize();
				CLog.Trace("AMD AutoUpdate Launched.");
				new MainWindow(Args[0].ToString().Trim()).Show();
			}
		}
		else
		{
			mutexOwned = true;
			CLog.Initialize();
			CLog.Trace("AMD AutoUpdate Launched.");
			new MainWindow(Args[0].ToString().Trim()).Show();
		}
	}

而在MainWindow中,我没有耗费太多时间就在它的构造函数中找到了疑似造成报错的对象:VersionInfo.xml。此后我又在Window_Loaded()事件处理中顺利发现了下载VersionInfo.xml的动作,而后还在objWebClient_DownloadFileCompleted()下载完成事件处理中看到了读取文件的操作,最后在ReadVersionInfo()函数中,我见到了解析XML文件的代码:

	public MainWindow(string notifyForProduct = "000")
	{
		ProductForNotify(notifyForProduct); // PS:选择要通知更新的软件,默认是"ALL",也就是"000"
		InitializeComponent();
		VersionInfoFilePath = AppDomain.CurrentDomain.BaseDirectory + "VersionInfo.xml";
	}

	private void Window_Loaded(object sender, RoutedEventArgs e)
	{
		if (!NetworkInterface.GetIsNetworkAvailable())
		{
			System.Windows.MessageBox.Show(this, "Internet connection not available.", "AMD AutoUpdate", MessageBoxButton.OK, MessageBoxImage.Hand);
			Environment.Exit(0);
		}
		else
		{
			DownloadVersionInfo(); // PS:下载版本信息文件
		}
	}

	private void DownloadVersionInfo()
	{
		try
		{
			string uriString = ConfigurationManager.AppSettings["VersionInfo"].ToString(); // PS:从程序目录读取<程序名.exe.config>配置文件,此处是读取 AMDAutoUpdate.exe.config 文件
			WebClient webClient = new WebClient();
			webClient.DownloadFileCompleted += objWebClient_DownloadFileCompleted; // PS:注册 objWebClient_DownloadFileCompleted 下载完成事件处理
			webClient.DownloadFileAsync(new Uri(uriString), VersionInfoFilePath);
		}
		catch (Exception ex)
		{
			CLog.Trace(ex.Message);
		}
	}

	private void objWebClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
	{
		ReadVersionInfo(); // PS:读取版本信息文件
	}

	private void ReadVersionInfo()
	{
		try
		{
			XmlDocument xmlDocument = new XmlDocument();
			using (StreamReader txtReader = new StreamReader(AppDomain.CurrentDomain.BaseDirectory + "VersionInfo.xml", Encoding.GetEncoding("ISO-8859-1")))
			{
				xmlDocument.Load(txtReader);
			}
			// ...省略业务逻辑代码 //
		}
		catch (Exception ex)
		{
			CLog.Trace(ex.Message);
		}
	}

从这几段代码里可以看到,在出现错误后,程序并没有清理下载的VersionInfo.xml。结合之前日志中的报错信息,如果是它出了问题,那么我就可以在程序目录里看到错误的VersionInfo.xml文件。而事实证明,也确实是这个文件出了问题——在程序目录中,VersionInfo.xml大小为0KB,也就是说,更新程序没有从AMD获取到这个文件。
但是这并不合理。首先我可以确定我的网络没有任何问题,我完全可以正常访问AMD的官方主页:amd.com;其次AMD这家公司截至当前(2025-06-05)也还在运作,我能访问他们的主页也是一个证明。于是我根据代码打开了程序目录里的AMDAutoUpdate.exe.config文件,从中提取出VersionInfo.xml的下载地址(https://www2.ati.com/drivers/patch/ec1b73b4-bc2a-4ca1-8431-c514730dbd90/versioninfo.xml)粘贴到浏览器进行访问。而结果是,我完全可以在浏览器中十分流畅地下载到这个文件。
此时我怀疑是AMD根据User-Agent对请求进行了过滤,于是我连接到了家里的树莓派,尝试通过curl访问这个文件,果然没有成功。但在我用curl -i查看响应状态时,我发现了302 Moved Temporarily错误。
curl访问xml文件

于是我加上-L参数,让curl跟随重定向,不过返回了403:
curl -L 访问xml文件

考虑到浏览器访问正常,那么意味着curl需要设置请求头伪造成浏览器访问。最后试出来需要加上Accept: */*Accept-Language: zh-CN,en-US,enAccept-Encoding: gzip以及User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139.0) Gecko/20100101 Firefox/139.0四个请求头才访问成功:
curl访问xml文件成功

curl成功访问文件后,再回头看AMDAutoUpdate。很明显,它既没有响应302状态码,也没有设置请求头,那么它自然不可能完成它的任务,也就会在被计划任务唤醒后就立即卡死。

posted @ 2025-06-06 00:17  XYZ59C  阅读(809)  评论(0)    收藏  举报