通过注册表修改系统PAC代理设置

最近在写一个代理工具的整合, 不过不便发到博客上来, 就说说里面单纯的技术问题, 今天先写这一篇.

修改代理的办法貌似不少, 常用的貌似就注册表和Win API – InternetSetOption, 一开始我当然是想从相对正规的渠道, API来搞定, 花了相当大的力气, 才搜到相关内容, 并且修改成我需要的样子. 不过代码被我删了… 所以… 就不能分享了, 这里直接说说通过注册表改PAC设置的问题.

首先, 为什么我最后要用注册表而不是Win API? 原因是我没找到Win API修改Dial-up和VPN的PAC设置的方法, 所以也是无奈之举. 毕竟很多用户, 比如我自己, 就是通过Dial-up或者VPN联网的. 那, 下面开始主体内容. (我使用的是C#)

1. 注册表位置

CurrentUser, Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections

2. 值

值的名称就是连接的名称, 值是字节数据, 所以需要简单地分析下结构. (后来有个学长提醒说, C++什么的里面处理这种东西特别方便, 一个结构体搞定, 想想貌似是那个道理)

1) 最前面4字节应该是版本号, Win 7下是0x00000046, XP下貌似是3D, 记不清了…
2) 紧接着的4字节是修改次数, 每次修改都应该+1.
3) 接下来的4字节是flags, 其实貌似只有第一个字节用到了, 后面三个字节始终都是0, 这里开启PAC, 把这个值设为0x00000005就可以了, 其他开关什么的, 需要的话自己试试吧.
4) 接下来的4字节是保存了一个或多个(http, socks, ftp等)代理服务器及端口的字符串的长度,  当然, 再接下来的这个长度的字节就是这个字符串的数据了.
5) 接下来的4字节是保存了代理的例外服务器的字符串的长度,  再接下来的这个长度的字节也自然就是这个字符串的数据了.
6) 然后我们需要的东西终于来了, PAC文件的字符串长度, 4字节, 和PAC文件的字符串.
7) 因为我只需要在计数器(第5~8字节)上 +1, 并修改PAC文件即可, 所以后面的数据直接拷贝.

C#代码片段如下, 相关变量请自助:

var data = key.GetValue(name) as byte[];
var newData = new List<byte>();

var pos = 0;

//skip head, 4 bytes
newData.AddRange(data.Skip(pos).Take(4));
pos += 4;

//modify count
newData.AddRange(BitConverter.GetBytes(BitConverter.ToInt32(data, pos) + 1));
pos += 4;

//config flags
newData.AddRange(BitConverter.GetBytes(configFlags));
pos += 4;

//skip proxy setting
var skipCount = BitConverter.ToInt32(data, pos) + 4;
newData.AddRange(data.Skip(pos).Take(skipCount));
pos += skipCount;

//skip passby setting
skipCount = BitConverter.ToInt32(data, pos) + 4;
newData.AddRange(data.Skip(pos).Take(skipCount));
pos += skipCount;

//now, pac file
skipCount = BitConverter.ToInt32(data, pos) + 4;

var pathByteList = new List<byte>();
foreach (var chr in path) {
    var chrBytes = BitConverter.GetBytes(chr);
    chrBytes = chrBytes.Take(chrBytes.Length – 1).ToArray();
    pathByteList.AddRange(chrBytes);
}
newData.AddRange(BitConverter.GetBytes(pathByteList.Count));
newData.AddRange(pathByteList);
pos += skipCount;

//the rest
newData.AddRange(data.Skip(pos).ToArray());

var chrs = new char[newData.Count];
for (var i = 0; i < newData.Count; i++)
  chrs[i] = (char)newData[i];

//set the reg value
key.SetValue(name, newData.ToArray());