Java编程中的流氓手段(1)——天下为公

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情
程序员应是创造者,创造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
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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:ceponline@yahoo.com.cn
 * @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中似乎金科玉律的访问限制,在我等流氓面前,已不复存在。


下载地址:http://download.csdn.net/source/486830
恶意软件家族全解析:从病毒木马到蠕虫流氓软件的识别与实战查杀 在网络安全领域,恶意软件是威胁系统与数据安全的核心载体。其工作原理基于代码注入、自我复制、网络传播等机制,旨在实现信息窃取、系统破坏或资源劫持。理解恶意软件的技术价值在于构建主动防御体系,而非仅依赖被动查杀。从概念上,病毒依赖宿主文件传播,木马伪装欺骗用户,蠕虫利用漏洞自动扩散,流氓软件则通过捆绑安装进行骚扰牟利。这些技术常混合出现,形成更复杂的混合威胁。在应用场景中,工程师的开发环境、服务器、嵌入式设备及内网测试平台,都是恶意软件的高价值目标。本文聚焦于恶意软件家族的行为模式辨析,并基于系统快照、深度排查 阅读详情

相关推荐

java中的流氓手段(1)

通过变更java字节码强转class中所有类型为public

android jni c/c++线程通过CallVoidMethod调用java函数出现奔溃问题

最近在移植p2p库到android平台,需要用到jni,最近在c线程了调用java函数的时候出现一个问题,假如在同一个线程调用java函数是没问题的,但在一个c线程了调用java函数就出现奔溃问题,下面就直接贴c线程里调用java函数的流程代码吧: 步骤1. 我这里的应用是,java处理视频播放,在java层写需要调用的函数,例如:private void recvData(String devid

hyl999的专栏 1万+

一种建立自己搜索引擎的流氓手段

方法的核心就是利用baidu或者google的硬盘搜索发现baidu的硬盘搜索都是本地有一个进程序监听本地的7878 端口利用这个原理实现流氓搜索引擎的方法如下 第一步 准备被搜索的材料 保存到d:/data目录 并且把所有的(文本)材料以.abc命名第二步 设置一下让baidu只对d:/data 目录索引 然后添加.abc扩展名 设置为只索引.abc文件第三步 分析本地搜

fansun的专栏 1187

流氓修炼之谜 揭开流氓软件的技术原理

ark1111的专栏 2581

年收入上百万的流氓软件的技术原理

cqfz123的专栏 4330

总结几种常见web攻击手段及其防御方式

本文简单介绍几种常见的攻击手段及其防御方式 XSS(跨站脚本攻击) CSRF(跨站请求伪造) SQL注入 DDOS web安全系列目录 总结几种常见web攻击手段极其防御方式 总结几种常见的安全算法 XSS 概念 全称是跨站脚本攻击(Cross Site Scripting),指攻击者在网页中嵌入恶意脚本程序。 案列 比如说我写了一个博客网站,然后攻击者在上面发布了一个...

anzhuan3270的博客 1728

不耍流氓,我们来正经谈谈什么才是最佳编程语言!

=6431065291664392706&group_flags=0)》中,笔者解析了选择一种编程

weixin_49317973的博客 171

web几种常见的攻击手段及其防御方式

XSS(跨站脚本攻击) CSRF(跨站请求伪造) SQL注入 DDOS XSS 概念 全称是跨站脚本攻击(Cross Site Scripting),指攻击者在网页中嵌入恶意脚本程序。 案列 比如说我写了一个博客网站,然后攻击者在上面发布了一个文章,内容是这样的 ,如果我没有对他的内容进行处理,直接存储到数据库,那么下一次当其他用户访问他的这篇文章的时候,服务器从数据库读取后然后响应给客户端,浏览...

callmeCassie的博客 403

SQL安全:常见手段

前面我们从基础的单表查询一直聊到优化,讲了SQL的很多内容。这一节我们来说说怎么让我们的数据库变得更安全。为了实现常见的业务场景,数据库会提供很多的功能。有一些功能如果被攻击者利用,就很容易获取到不应该让其获取到的信息。比如拼接、比如拼接。常见的手段,可以在进行分类。

Innocence_0的博客 1130
上一篇: JSP/Servlet中的汉字编码问题
下一篇: UML基础:统一建模语言简介
cping1982
博客等级 码龄19年 2976粉丝 277原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值