利用Java编写简单IIS日志清理工具
| 1楼 拿下XXX网站,提权得到管理员权限以后,大家是不是就一走了之呢?是不是忘了什么很重要的事情呢?没错,清理日志!勤快点的管理员会定时分析系统日志,看看系统什么时候发生过什么事情;细心的管理员则可以从日志里面看出我们跑进他们系统的脚印哦。现 在网上提供的日志清理工具好多都是直接删除整个日志文件的,管理员在查日志文件时发现日志没了,不用说也知道服务器被黑,这样做是比较傻瓜的。因此,我们 就需要可以清理我们指定IP的日志这个功能。网上找了一下,发现iisantidote这个小工具可以实现,但没提供源码。我就本着开源的思想,用 Java写了这么一个小工具。本文没有做太复杂的功能,实现清理指定IIS文件的日志就OK了,即在IIS日志文件里面找到我们指定IP的记录,然后删 除。 在开始写程序前,我们引入下面三个包。 import java.io.*; //封装了java对文件的一些操作 import java.util.ArrayList; //java封装好了链表,我们无需再自己重新写,方便了很多 import java.util.ListIterator; //对链表的一些操作,非常方便 读IIS日志 public void readLog() { try { BufferedReader bFile = new BufferedReader(new InputStreamReader(new FileInputStream(fileName))); String data; while ((data = bFile.readLine()) != null) {//判断是否读到空数据,空则停止 logArray.add(data);//保存数据 } bFile.close();//处理完文件以后一定要关闭文件读取流 } catch (FileNotFoundException e) {//处理文件异常 System.out.println("文件无法找到"); } catch (IOException e) {//处理输入输出异常 e.printStackTrace(); } } 我们先一下BufferedReader的构造方法。 BufferedReader(Reader in)用于创建一个使用默认大小输入缓冲区的缓冲字符输入流。为什么我们要选择这个类来操作文件呢?对于IIS的日志文件,如果访问量很大,那么产生的日 志就会非常庞大。如果使用一个未带缓冲区的方法来读一个大文件,会费很多的时间,程序也很容易假死,而且效率也很低下。因为这个类里面的参数是 Reader,所以我们就要用“new InputStreamReader(new FileInputStream(fileName))”来获得一个Reader类的对象。fileName就是我们输入的IIS日志文件的路径。 bFile通过readLine()每次读入一行日志记录,然后将这些记录全部存储到一个logArray的数组里面,logArray的类型是Array。我们前面说过了,Array封装了很多链表操作方法,add()就能直接将我们的数据添加进链表里。 处理IIS日志记录,删除存在指定IP的记录 public void execLog() { ListIterator li = logArray.listIterator(); String temp; while (li.hasNext()) {//判断是否到了链表尾部 temp = li.next().toString();//将链表数据转换成String类型 try { if (temp.split(" ")[1].toString().equals(ip)) {//与指定的IP进行比较 } else //过滤指定IP的记录 newLogArray.add(temp); //添加到新的日志链表 } catch (Exception e) {//处理异常 e.printStackTrace(); } } } ListIterator 是一个接口,允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。在这里我们只用到了hasNext()和next()方 法。顾名思义,第一个是判断是否还有后续元素,第二个就是获得后续元素,我们通过循环判断所有的元素即可。temp是一个String类型的变量,每次只 存储一条日志记录,记录的格式是“时间 客户IP 访问类型 标志”,对于我们来说,我们只关心客户IP,此时调用String类的spilt()方法来获得就可以了。 temp.split(" ")能将一个String类型的变量temp按空格分成一组数组,从上面的记录格式我们可以看出,客户IP是在第二个位置的,所以我们就可以通过 temp.split(“ “)[1]来得到客户IP。equal()方法就是比较了。整个IF-ELSE里面是将与IP匹配的记录略去,然后存到新的newLogArray里面, 这样得到的newLogArray链表就是没有我们自己IP的日志列表了。 |
2楼 修改IIS日志文件 public void writeLog(ArrayList temp) { ListIterator li = temp.listIterator(); //temp就是我们要写到日志文件的日志记录链表 try { BufferedWriter bw = new BufferedWriter(new FileWriter(fileName)); while (li.hasNext()) { bw.write(li.next().toString() + "\n");//逐行写入,后面再加个换行 } bw.flush();//关闭文件之前,一定要先flush() bw.close(); } catch (IOException e) { e.printStackTrace(); } } 写文件同样要用到带缓冲的方法,就是BufferedWriter,这里的理论跟读文件一样,就不再细说了。我们依然利用循环来将链表中的记录写进文件,最后那个换行一定要加上去,如果不加的话,写进去的时候是没有换行的。 之 后,最重要的工作就是把我们上面写的代码连接在一起了。在我们修改IIS日志文件的时候,如果只是修改过往日志,那还好,直接修改就行了。但是如果修改的 是当天日志,那可就不同了,因为IIS仍在运行,正在操作那个日志文件,我们就只有看着的份,写是写不了的了。所以,我们在修改之前,一定要把IIS先给 停了。 public void exec() { try { Process p = null; p = Runtime.getRuntime().exec("cmd /c iisreset /stop"); execResult(p);//打印DOS命令执行返回的数据 p = Runtime.getRuntime().exec("cmd /c net stop w3svc"); execResult(p); readLog();//读日志,前面已经介绍 execLog();//处理日志 writeLog(newLogArray);//修改日志 p = Runtime.getRuntime().exec("cmd /c iisreset /enable"); execResult(p); p = Runtime.getRuntime().exec("cmd /c iisreset /start"); execResult(p); p = Runtime.getRuntime().exec("cmd /c net start w3svc"); execResult(p); } catch (IOException e) { e.printStackTrace(); } } 还 记得2007第12期《利用Java写自己的专属后门》上面讲的Process这个类吗?当时我们是用来运行系统命令的。这里我们为什么要执行 “iisreset /stop”和“net stop w3svc”呢?因为如果只用后者,在Java里面有时是无法将IIS直接停掉的,所以我们就必须先将IIS停掉,然后再停w3svc,后面对日志的操作 就不做介绍了。这里我还连续用了三组命令来启动IIS,为什么会那么麻烦呢?首先“iisreset /enable”,因为前面的“iisreset /stop”在我测试的时候有时会将IIS给禁用了;然后再“iisreset /start”和“net start w3svc”,因为后面那个命令只启动w3svc服务而没有启动IIS服务,所以为了避免出现意外就全部都加进去了。 说到这里,这次的Java版 日志删除小工具就算是完成了。对于这个小程序,实现的只是一个小小的功能,我们还可以发挥想象,继续扩展它的功能。比如我们可以一次性处理所有的日志文 件,添加多线程处理,处理其他类型的日志。说到其他类型的日志,其实我们只要知道日志的数据组织存放结构,就可以将这个类型的日志清除工具写出来的。至于 这些功能的扩展,就交给聪明的读者去完成吧。 |