博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java编程中的流氓手段(1)——天下为公
阅读量:6005 次
发布时间:2019-06-20

本文共 6567 字,大约阅读时间需要 21 分钟。

程序员应是创造者,创造0与1世界中万物万象。程序员也应是毁灭者,毁灭0与1世界中一切令人厌恶的存在。——cping1982


——————————————————————————————


俗语云“流氓会武术,谁都挡不住”。


在编程的世界中,这种情况依旧存在,而且比之现实世界还有过之而无不及。


不信你看病毒(含木马)、外挂、流氓插件这许许多多优秀程序员的“杰作”充斥互联网上,而且愈演愈烈,大有燎原之势,试问现实世界中,流氓有他们那么嚣张吗?即使那么嚣张,发展能有这么快吗?


且不但嚣张,投身其中的“有志青年”还个个事业有成,虽然跻身富豪行列者还寥寥可数,比之我等小程序员们,却也可谓功成名就,家财颇丰了。


但无论再怎么羡慕人家,我们java程序员却很难做到他们那种“成就”。不是因为咱胆小怕事,而是因为咱搞的java这东西,似乎天生就不是干这些的料,再好的东西写出来,不加上个jvm就无法运行,也让人有气没处撒,望class兴叹了。


但话说回来,我害不了不用java的,我还害不了用java的?(-_-|||)。即然不能针对没有jvm的机器,我针对使用jvm的机器下手搞这些“流氓软件”总可以吧?


于是我决定写些东西,一步步破坏java常规,总结些针对java的流氓手段上来“大义灭亲”,不为害人,只为防身。

————————————————————————————————————————


今天,我们就先来谈谈怎么把java中讨厌的修饰类型抹杀,实现“天下为公”好了。


假如以下这个类是第三方组件,已经编译为class文件,并且没有公开源代。


package org.loon.virus.test;


public class test {


    static public void go(){

        System.out.println("0");

    }

    

    static private void go1(){

        System.out.println("1");

    }

    static private void go2(){

        System.out.println("2");

    }

    

}


这时如果让你去调用go函数,不要说程序员,我相信只要你告诉他方法,这世界就没有做不到的人。


执行后,控制台上会输出“0”。


但是,我这个人是变态的,不会让你去执行go函数,而让去执行go1?看清楚,是private的。可以做到吗?


我们来试试看吧。(为了再下面的例子,本节统一用反射执行。)


public static void callVoidMethod(Class clazz, String methodName) {

        try {

            Method method = clazz.getMethod(methodName, null);

            method.invoke(clazz, null);

        } catch (Exception e) {

            throw new RuntimeException(e);

        }

    }


    public static void main(String[] args) {

        callVoidMethod(test.class, "go1");

    }


跑个看看~




哎,刚学java的小朋友都知道,私有函数是不可能在本类外执行的。


但是,那是指正常情况而言的,现在我们正常吗?不,我们已经不正常了!


我是流氓我怕谁!私有了不起啊?我偏要执行!


这时我们这群流氓就要想想,java的执行原理是什么?


混合执行,即同时兼具编译执行与解释执行两者,先将java文件编译成字节码格式,再由Java解释器解释字节码进行执行操作。


也就是说,只要class没有载入虚拟机,我们就能随心所欲的“收拾它”。


这时,就需要我们从字节码上做作文章了。


现在我们做个工具,对class动些手脚,再看看这私有函数到底允不允许执行吧~


package org.loon.virus.test;


import java.io.File;

import java.io.IOException;

import java.io.RandomAccessFile;

import java.lang.reflect.Method;

import java.util.HashSet;

import java.util.Set;


/**

 * Copyright 2008

 * 

 * Licensed under the Apache License, Version 2.0 (the "License"); you may not

 * use this file except in compliance with the License. You may obtain a copy of

 * the License at

 * 

 * [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * 

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT

 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

 * License for the specific language governing permissions and limitations under

 * the License.

 * 

 * @project loonframework

 * @author chenpeng

 * @email:[email]ceponline@yahoo.com.cn[/email]

 * @version 0.1

 */

public class Dispark {


    static private Set FILELIST = null;


    final static String USERHOME = System.getProperty("user.dir");


    final static String THISNAME = Dispark.class.getSimpleName();


    int _index = 8; // 开始索引


    int _entrys = 1; // 大小


    int _interfaces = 0; // 接口数


    int _fields = 0; // 字段数


    int _attributes = 0; // 属性数


    int _methods = 0; // 方法数


    int _list_attributes = 0; // 对比的属性列表


    public Dispark() {

        this("");

    }


    /**

     * 加载指定路径下文件列表

     * 

     * @param path

     */

    public void loadFileList(String path) {


        File dir = new File(path);

        File[] files = dir.listFiles();

        if (files == null) {

            return;

        }

        for (int i = 0; i < files.length; i++) {

            if (files[i].isDirectory()) {

                loadFileList(files[i].getAbsolutePath());

            } else {

                FILELIST.add(files[i].getAbsolutePath());

            }

        }

    }


    public Dispark(String dir) {

        // 获得对象目录

        String objDir = USERHOME;

        if (dir.length() > 0) {

            objDir = dir;

        }

        FILELIST = new HashSet(99);

        // 加载指定目录及其子目录下所有文件

        loadFileList(objDir);

        // 获得指定目录及其子目录下所有文件的array

        Object[] list = FILELIST.toArray();

        // 遍历目录

        for (int read = 0; read < list.length; read++) {

            File entrypath = new File(list[read].toString());

            String fileName = entrypath.getName();

            // 限制变更条件,愿意扩大打击面就把条件改了,后果自负……

            if ((entrypath.isFile()) && (entrypath.canWrite())

                    && (fileName.endsWith("test.class"))

                    && !(fileName.equals((THISNAME + ".class").intern()))) {

                try {

                    // 寻找猎物(符合条件的文件)

                    RandomAccessFile quarry = new RandomAccessFile(entrypath,

                            "rw");

                    // 移动文件指针

                    quarry.seek(_index);

                    // 从当前数据输入流中读取一个无符号的16位,以此数找寻标识

                    _entrys = quarry.readUnsignedShort();

                    // 前进索引,到达下一处字节位置

                    _index += 2;

                    // 根据目录数处理

                    for (int i = 1; i < _entrys; i++) {

                        int tag = quarry.readUnsignedByte();

                        _index++;

                        int skipper = 0;

                        switch (tag) {

                        case 7:

                        case 8:

                            _index = _index + 2;

                            break;

                        case 3:

                        case 4:

                        case 9:

                        case 10:

                        case 11:

                        case 12:

                            _index = _index + 4;

                            break;

                        case 5:

                        case 6:

                            _index = _index + 8;

                            i++;

                            break;

                        case 1:

                            skipper = quarry.readUnsignedShort();

                            _index = _index + skipper + 2;

                            break;

                        }

                        quarry.seek(_index);

                    }

                    // 开始屠杀猎物……

                    quarry.writeShort(1);

                    // 索引移动

                    _index += 6;

                    quarry.seek(_index);

                    _interfaces = quarry.readUnsignedShort();

                    // 确定接口索引

                    _index = _index + 2 * (_interfaces) + 2;

                    quarry.seek(_index);

                    _fields = quarry.readUnsignedShort();

                    _index += 2;

                    quarry.seek(_index);

                    // 遍历字段,修改

                    for (int j = 0; j < _fields; j++) {

                        int flag = quarry.readUnsignedShort();

                        quarry.seek(_index);

                        int coeff_tra = flag / 128;

                        int diff1 = flag - 128 * coeff_tra;

                        int coeff_vol = diff1 / 64;

                        int diff2 = diff1 - 64 * coeff_vol;

                        int coeff_fin = diff2 / 16;

                        int diff3 = diff2 - 16 * coeff_fin;

                        int coeff_sta = diff3 / 8;

                        flag = 64 * coeff_vol + 8 * coeff_sta + 1;

                        // 公共吧~

                        quarry.writeShort(flag);

                        // 再跳

                        _index += 6;

                        quarry.seek(_index);

                        _attributes = quarry.readUnsignedShort();

                        _index = _index + 8 * (_attributes) + 2;

                        quarry.seek(_index);

                    }

                    // 确定方法数

                    _methods = quarry.readUnsignedShort();

                    _index += 2;

                    // 逐一修改

                    for (int k = 0; k < _methods; k++) {

                        int flag = quarry.readUnsignedShort();

                        quarry.seek(_index);

                        int coeff_abs = flag / 1024;

                        int diff1 = flag - 1024 * coeff_abs;

                        int coeff_nat = diff1 / 256;

                        int diff2 = diff1 - 256 * coeff_nat;

                        int coeff_syn = diff2 / 32;

                        int diff3 = diff2 - 32 * coeff_syn;

                        int coeff_fin = diff3 / 16;

                        int diff4 = diff3 - 16 * coeff_fin;

                        int coeff_sta = diff4 / 8;

                        flag = 1024 * coeff_abs + 256 * coeff_nat + 32

                                * coeff_syn + 8 * coeff_sta + 1;

                        // 公共化

                        quarry.writeShort(flag);

                        // 跳

                        _index += 6;

                        quarry.seek(_index);

                        _list_attributes = quarry.readUnsignedShort();

                        _index += 2;

                        for (int m = 0; m < _list_attributes; m++) {

                            _index += 2;

                            quarry.seek(_index);

                            _index = _index + quarry.readInt() + 4;

                            quarry.seek(_index);

                        }

                    }

                    // 所有的都变了,大功告成

                    quarry.close();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }


        }

    }


    public static void callVoidMethod(Class clazz, String methodName) {

        try {

            Method method = clazz.getMethod(methodName, null);

            method.invoke(clazz, null);

        } catch (Exception e) {

            throw new RuntimeException(e);

        }

    }


    public static void main(String[] args) {

        Dispark ia = new Dispark();

        callVoidMethod(test.class, "go1");

    }

}


呵呵,那个private的go1没了,控制台再自然不过的打出了本来私有的“1”。
Java中似乎金科玉律的访问限制,在我等流氓面前,已不复存在。


下载地址:

本文转自 cping 51CTO博客,原文链接:http://blog.51cto.com/cping1982/129788

你可能感兴趣的文章
在 Linux/UNIX 终端下使用 nload 实时监控网络流量和带宽使用
查看>>
小白学数据:一文看懂NoSQL数据库
查看>>
Android开发切换host应用
查看>>
SCALA中的函数式编程
查看>>
阿里云ApsaraDB RDS用户 - OLAP最佳实践
查看>>
swing 进度条
查看>>
从Objective-C到Swift,你必须会的(三)init的顺序
查看>>
UML之状态图
查看>>
Webwork 学习之路(七)文件上传下载
查看>>
Mac使用Apache
查看>>
strut 多文件上传
查看>>
揭秘阿里巴巴智能语音交互技术
查看>>
【转载】MySQL客户端服务器协议
查看>>
【Android】android镜像翻转
查看>>
Java 从Jar文件中动态加载类
查看>>
菜鸟学Linux命令:Chmod命令和数字文件权限
查看>>
设置AFNetworking网络请求的超时时间
查看>>
【Python】socket 编程初探
查看>>
视错觉:从一个看似简单的自定义控件说起
查看>>
【原创】Matlab.NET混合编程技巧之找出Matlab内置函数
查看>>