Adding New Functions to Compiled Code

在Ubuntu 18.04编译Android 8.1 在ubuntu 18.04编译android 8.1 2018.08.06 在看了许多教程后自己也动手实施,道路可以说简单也可以说难。 硬件要求: 越高越好,不建议在虚拟机内编译 内存越大越好,推荐200G,在这里就不赘述怎么安装ubuntu双系统了,网上教程很多,有空写一教程出来 安装并配置git sudo apt-get install git -y git co... 阅读详情

http://sandsprite.com/CodeStuff/add_function.html

Adding New Functions to Compiled Code



Tools used:
  • OllyDbg - free debugger - Oleh Yuschuk
  • HIEW - line assembler for hacking our compiled binary - Eugeny Suslikov
  • iidKing - add imports to PE header - SantMat
  • LordPE - PE editor/viewer - yoda
  • VC6 - create sample projects and dll
  • Winhex - hexeditor/viewer
Download example binaries and source


Note: Also check out the CaveWriter tool I made for an alternative method to applying these patchs that might be a bit easier. (Screenshot)


This tut is just a quick fun example of what you might do with your new found RCE skills on a bored and rainy day.

Seriously though, there are times when you need to tweak a compiled app of which you do not have the source for.

This trainer will walk you through an example application and show you one such example.

Source and binaries are provided in the download package so you can directly walk along and see what I am talking about and follow along with me both in the source and in a debugger.

First lets describe a problem. We have an App that has a function that takes one numeric argument. We need to alter this number at times but the program provides no way to do so.

So this source is a mock up of this situation, and shows us an answer.

In the simplest of terms, our main app has a function call with one numeric argument.

void main(void){
	int c = 0;
	normal(c);
}
The function "normal()" is also quite simple and just displays the value passed to it.

__stdcall int normal(int c){
	printf("I am normal and I see %x/n",c);
	printf("Press any key to continue...");
	getche();
}
Your goal should you choose to accept it, is to implement a way so that you can interactivly change the value passed to normal() at run time.

If we look at the asm that calls the function normal() we might see something like this:

.text:004010BA _main           proc near               
.text:004010BA
.text:004010BA varC            = dword ptr -4
.text:004010BA
.text:004010BA                 push    ebp
.text:004010BB                 mov     ebp, esp
.text:004010BD                 push    ecx
.text:004010BE                 mov     [ebp+varC], 0   ;initialize variable
.text:004010C5                 mov     eax, [ebp+varC] ;place it in eax register
.text:004010C8                 push    eax             ;push onto stack as arg
.text:004010C9                 call    normal          ;call function normal()
.text:004010CE                 xor     eax, eax
.text:004010D0                 mov     esp, ebp
.text:004010D2                 pop     ebp
.text:004010D3                 retn
.text:004010D3 _main           endp
So what is the easiest way we can insert a binary patch to the compiled executable to interactively edit this argument value?

After thinking about some ways to do this I decided the easiest way to write an external dll that will provide a basic UI (in this case a console window) which I will then call from a small asm stub I patch into the binary.

These tricks are not new, I remember reading a tut on this kinda stuff a while back. I just wanted to try it myself so thought I would write this as I went to help others along.

So here is our basic outline

  1. compiled code calls function with one numeric argument.
  2. we change this function call and hijack execution to our own code which allows us to interactively change the value.
  3. altered value is sent back to the original function and everything is restored as if nothing happened.
Why did I choose to use an external DLL to implement the main functionality? There are a couple reasons:

  1. No space limitations
  2. Less asm to debug
  3. Dll can be written in a higher level language such as C
  4. No limitations on what functions you can use in the DLL and no need to import new libraries with LoadLibrary
Before we can use our DLL function, we need to know how we are going to load it and call it. We could call LoadLibrary and GetProcAddress manually in the asm patch, or we could be extra lazy and modify the targets import table so that our dll is automatically loaded for us by the Windows Loader.

Changing the import table sounds like more fun so lets do that :)

So first thing we do is create a sample app and debug all the code to get ourselves started. Check out the source for details (Note if you recompile the apps, offsets will likely change. I have included an original copy of the exe for you to experiment with if you want to make the mods yourself as we go)

If you look at the main app, you will see the basic layout. At the bottom you also see some inline asm tests you can try to get an overview of what we are ultimately going for.

After our UI function is created and debugged, we house it in a stdcall dll and export it. With that done, our DLL is now made, and we need to add it to the import table of our compiled target. For this we use a very cool program named iidKing.

You should be able to figure it out by just playing with it, basically you just enter the dll name to add and the dll function to import and hit a button couldn抰 be much simpler :)

After iidKing says happy things to you, fire up LordPE again and check the import table just to double check the results. You can also load the exe up in your debugger and look at the executable modules loaded to double check that its really there. Below is how the import table now looks in LordPE:



IIDKing also generates a file that will give you the offset of the new function you added and how to call it in asm.

ConfirmPID: call dword ptr [40A044]

Ok Cool, now our UI function is in place and ready to be called in an easy to use way. Now we need to get execution there.

Lets take a look at some example asm code of what will need to happen for this to all work:
void main(void){

	int c = 0;
	
	__asm{
				mov c,2     ;set initial val for arg
				mov ebx, c
				push ebx    ;push arg on stack
				jmp hack    ;was call normal
	back:
				mov c, eax
				jmp done

	hack:
			call ConfirmPID  ;call our dll function
			push eax         ;put return value on stack
			call normal      ;call original function
			jmp back         ;resume execution as normal
	done:
		
	}
}
Lets explain the above layout. While the majority of our new code is housed in our DLL, we are still going to have to write some stub in asm to get us to it.

First, we need to hijack execution just before the real function call.

In the disasm of the main function we saw the call we are interested in. In hiew this looks like
004010C9: E8 BC FF FF FF                   call     .00040108A
We can see we have 5 bytes to play with (more if we have to but then we would have to execute the other overwritten instructions somewhere else)

This raises a question if we hijack execution here...where are we going to send it? We need a place for our new instructions to sit in the file.

Here comes the concept of "caves" Basically we just need a section in the binary file that is mapped with execution privileges in memory and has a spot where there is no code yet.

To find a suitable cave, lets check out its section tables. Below is another screen shot of LordPE:



This screen shot is showing you allot. So let me explain. First, look at the Back most window that lists all the PE sections. The windows on top are further describing the .text section. From these windows, we can see that the .text section starts at raw file offset 1000h, and is 5000h bytes long. The button on the middle form breaks down the flags value and brings up the topmost screen that shows what flags are set. As we can see, it is an executable section.

Looking at the main section table again, we see that the next PE section, .rdata starts at raw file offset 6000h, this is right after the .text section ends.

The intresting thing to note, is that the virtual size (the size in memory) of the .text section is not quite using up the entire 5000h bytes that are laid out for it in the file. This means that there is a slight gap between the two sections in the file.

Lets check out the file in a hexeditor:

Remember .text started at 1000h and its raw size is 5000h bytes long, 
         This means its spans the raw file offset from 1000h to 6000h
         Also note that its virtual size (size mapped into memory) is
         only 4E5Eh, which means that there is some unused space as shown
         below


Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00005E50   C0 74 06 0F B6 45 0B C9  C3 83 C8 FF C9 C3 00 00   纓..E.擅內擅..
00005E60   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005E70   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005E80   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005E90   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005EA0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005EB0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005EC0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005ED0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005EE0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005EF0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005F00   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005F10   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005F20   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005F30   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005F40   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005F50   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005F60   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005F70   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005F80   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005F90   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005FA0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005FB0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005FC0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005FD0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005FE0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00005FF0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00006000   7A 67 00 00 B2 65 00 00  D0 65 00 00 E2 65 00 00   zg..瞖..衑..鈋..
Yup..thats a nice pad for us and more than enough room for us to add in our small asm stub.

This extra space is totally unused, and not loaded into memory. Next we need to assure that whatever instructions we place in there, will be loaded into memory. We do this by altering the .text section attributes in the PE header with LordPE.

Right now the virtual size of this section is only 4E5E, because that is all the compiler needed. We need a little more, so lets change the virtual size of the .text section all the way up to 4FFF which is the max size we can use seeing how the entire raw size is only 5000.

Once that is done, we now have a suitable place to store our patch code. Next comes the actual patching :)

Above we already listed where in the disassembly the actual function call occurs
004010C9: E8 BC FF FF FF                   call     .00040108A
At this point, the argument is already on the stack and stuff is ready to happen....we just need other stuff to happen.

As shown in our inline asm code above, at this point we now the program to call our new dll function, call the original function with our modified data and resume execution. Before any of this can happen, we need to transfer the execution to our base asm stub.

For this we need to patch the original function call to instead jump right to our new code.

For this example, I choose to start my asm stub at raw file offset 5E70h. To get execution there all we have to do is replace that original function call with a jump to our new code as such
.004010C9: E9 A2 4D 00 00    jmp      .000405E70   ;this was the call normal()
One thing to pay close attention to when you are patching like this is how many bytes the instructions take. In both the original call, and our new jump, the instructions take a total of 5 bytes. This is very important.

If our jmp had taken more bytes than what we were replacing, we would have been overwriting other instructions which we would have had to make up for in our asm stub. Also if you have to overwrite other instructions..make sure you overwrite them entirely and dont leave some stray bytes that will totally change the meaning of the next instructions. (NOP out loose ends danielson)

Ok, so now instead of our function call, we will be redirected to our stub location. Now we need to enter the actual asm stub. Here is what it all looks like when you put it all together using HIEW.

.004010C5: 8B45FC         mov       eax,[ebp][-0004]
.004010C8: 50             push      eax
.004010C9: E9A24D0000     jmp      .000405E70   ;this was the call to normal()
.004010CE: 33C0           xor       eax,eax
.004010D0: 8BE5           mov       esp,ebp

.00405E70: FF1544A04000   call      d,[00040A044] ;address from iidKing for dll fx
.00405E76: 50             push      eax           ;return value from our dll
.00405E77: E80EB2FFFF     call     .00040108A     ;original "normal()" function
.00405E7C: E94DB2FFFF     jmp      .0004010CE     ;jmp back to next instruction
The normal function took one int arg, which is already on the stack for us. Our dll function takes the same int arg, and just gives us a chance to change it by popping up its own console if one was not already present. This gives us a dirty simple UI to interact with the user.

With all the changes now made, all we have to do is run it in Olly and see if we screwed anything up ;)

Trace along with the example or just double click and pray :P Turns out all our hard work paid off and works just as expected.

I have included all source code used in this tut in the package. Note that if you recompile offsets will likely change.

If you want to try to make the mods yourself, I have included an original unaltered exe as well as an altered one so you can step through it all in the debugger to watch it all in action.

This is the simplest case scenario of hacking in the ability to interactively alter a function with one numeric argument.

Anyway..enjoy...it was fun and I thought it would make a good trainer :)

-dzzie <dzzie at yahoo.com>


Copyright Sandsprite.com 2003

Ubuntu 16.04(18.04) 编译安卓4.4.4_r1系统源码 编译安卓系统源码 编译环境: Nexus5 + Ubuntu16.04 64bit 在新安装的ubuntu 18.04 64bit下编译通过 一、下载安卓系统源码 国内可以通过清华镜像站 https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/ 来下载 sudo apt-get install curl python git -y git conf... 阅读详情

相关推荐

ROS应用之如何配置RTOS满足机器人系统中的实时要求

实时操作系统(RTOS)基本概念实时操作系统(RTOS)是设计用于实时应用的操作系统,其主要目标是在确定的时间内完成任务。RTOS的任务调度算法和优先级控制机制能够确保高优先级任务按时完成。精确的传感器数据采集:传感器数据需要在规定时间内采集并传输给控制系统。快速响应外部事件:对于控制系统,需要确保指令在最短的时间内得到响应。任务的调度周期:任务的周期可以通过公式计算,其中 ftask 是任务的调度频率。优先级分配。

weixin_68094467的博客 1009

ubuntu10.04下make android1.5

Ubuntu10.04编译android1.5源码出错问题解决   环境:Ubuntu10.04     android1.5源码 make: (1)/bin/bash: bison: command not found 解决:$ sudo apt-get install bison (2)make: *** No rule to make target `Please-ins...

scfofo的博客 153

记一次使用STM32F042K6芯片内部HSI48M时钟导致CAN总线报错问题

深入去解决某个问题时,也会加深你对其它部分的了解和思考,比如这里让我又重新了解和CAN的采样点和CAN报错机制。

ApexYuan 861

Ubuntu 10.04下Android的内核和文件系统编译

<br /><br />1 、下载内核和文件系统 <br />1.1 下载文件系统 <br />1) Git的安装 <br /> 在 Ubuntu 10.04上安装 git只要设定了正确的更新源,然后使用 apt-get就可以了,有什么依赖问题,就让它自己解决吧。其中 curl是一个利用 URL语法在命令行下工作的文件传输工具,会在后面安装 Repo的时候用到。 (貌似 Ubuntu10.04已经默认安装了 git1.7.04,所以这步就不需要了 )<br />系统提供了默认下载软件包的地址

tomi2010的专栏 475

ADI官方例程HDL和No-OS生成Vivado工程

这一步是选择下载源,一般都是选择国内镜像,因为国外的源太慢了,这里选择阿里的镜像,如果没有这个选项可以在下面的User URL里添加就行,选择好源后然后点击下一步。下一步会从你选择的源上下载软件包目录,如果提示Unable to get setup from https://xxxxxx/,返回上一步,选择别的源,例如第二个163网易的源。然后就是你想要安装在哪了,下面的选项好像会决定环境变量存放在哪,不过一般都是个人电脑选择第一个默认的就行,然后点下一步。下好之后双击打开,就是这个界面了,直接点下一步。

代码匠的博客 3833

西门子V90 PN伺服控制核心:FB284功能块详解与实战

在工业自动化中,伺服定位控制是运动控制的基础环节,其本质是PLC通过PROFINET协议与伺服驱动器实现高速、确定性数据交互。FB284作为西门子为V90 PN定制的标准化功能块,封装了GSD映射、状态机管理与周期性PDO同步机制,将底层寄存器操作抽象为高可靠调用接口。相比MOVE指令或MC_MoveAbsolute等通用方案,FB284显著降低时序错乱风险,提升多轴同步精度与故障响应能力。它广泛应用于包装、灌装、装配等中端产线,尤其适配S7-1200/1500平台下的快速部署与现场维护。本文聚焦V90 P

weixin_42696271的博客 300

android 模拟器 sd卡文件 fileexport,linux下android模拟器的启动及SD卡的使用介绍.pdf...

主机配置:32 位XP ,vbox 虚拟机,32 位ubuntu10.04 ,android2.2 源码,JDK1.51、编译android2.2 源码编译环境准备好之后,在终端切换到android 源码所在的目录执行命令$ source build/envsetup.sh或者$ . build/envsetup.sh再执行:make漫长的等待时间,大概要3 个多小时吧,你可以出去玩儿了。机器在全...

weixin_39783156的博客 163

用Multisim仿真一个9V供电的双工对讲机:从电桥原理到LM1875功放调试全记录

本文详细介绍了使用Multisim仿真9V供电的双工对讲机全过程,涵盖电桥原理、NE5532前置放大设计、LM1875功放调试及双工通信实现。通过实战案例解析,帮助读者掌握模拟电路设计与调试技巧,提升电子工程实践能力。

weixin_28678831的博客 116

ubuntu10.04下android2.2源码编译

转自楚广明的博客:http://www.cnblogs.com/chu888chu888/archive/2010/11/24/1886385.html      万分感谢!android2.2源码编译环境:--Ubuntu10.04 (X86) + android2.2 + JDK1.6注意:官方声明,32位系统下JDK必须用1.5---这是因为编译android api docs 需要1.5。要用JDK1.6必须用64位系统---为什么是64目前不得而知。要是想一次成功,最好还是按照官方说的用JDK

851

PCL 直通滤波

内容抄自优快云点云侠:[【2024最新版】PCL点云处理算法汇总(C++长期更新版)](https://blog.youkuaiyun.com/qq_36686437/article/details/114160640)。质量无忧,永久免费,可放心复制粘贴。

m0_51204289的博客 906

微信小程序中使用画布canvas实现动态心电图绘制

近期,接了个项目,三端(小程序、PC、公众号)同步开发,PC端没的问题,以前一直做的就是PC端,但是小程序和公众号之前没有做过,只能通过这个项目,边做边学了。人家都说小程序用原生的特别难,大部分都用uniapp开发,说是这个方便快捷,还能写app呢,因为我们的项目,需要用到蓝牙采集数据、画布画仪表盘以及心电图等,所以我们不太敢用uniapp开发,硬着头皮开始用原生开发。开发的过程中,也遇到过很多问题,但是好在经过我们团队的不懈努力,问题基本都解决了。下面我就来分享一下,在小程序中,如何通过canvas。

穆雄雄的博客 3652

Ubuntu10.04 32bit Compile Android2.2

Ubuntu10.04 32bit Compile Android2.2http://iopenfree.appspot.com/2010/10/25/code.html 1 repare Base environment 2:repo sync ->download Android latest Code 3:make 1:issue "You are attempting to build on a 32-bit system" How to fix: tommy@tommy-laptop

jiang_dlut 889

修改yolov8使支持单通道图像输入

默认支持BGR三通道图像输入,但是在很多工业场景下,存在很多灰度图像的场景,因此对yolov8代码做一些修改以支持单通道图像输入,满足项目实际需求。训练时,只需要在 data 的 yaml 文件中,添加 ch=1 即可。

mingo_敏 5779

Ubuntu 10.04环境下载&编译Android-2.2.1 (froyo) 源代码

<br />应一个在电信做android开发的哥们要求,帮忙把Goole未在sdk中打包的API(即:mms彩信功能),打包到自己编译的 sdk里面。偶用了差 不多5天+5夜的时间,虽然没有成功。但对于Ubuntu 10.04环境下载&编译Android-2.2.1 (froyo)源代码这个过程是相当熟悉啦,来来回回,在虚拟机里面做了5遍!其中的辛苦与开心只有自己才有深刻的体会。现在分享给大家,同时也感谢网络 上的筒子们。<br />1. 前言<br />本文叙述了如何从零开始搭建基于Googl

Coleman's blog 581

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Ubuntu 10.04环境下载&编译Android-2.1_r2源代码

  本文叙述了如何从零开始搭建基于Google官方Android 2.1-r2源码的开发环境,包括如何下载源代码、编译源代码,以及在模拟器中运行编译生成的镜像。文中开发机是基于Ubuntu 10.04的,同样适用于其他版本的Ubuntu。 [b] 2. 下载[/b][b]JDK 1.5 [/b]编译Android源码需要JDK1.5版(主要是需要其中的javadoc),1.6版是不兼容的...

rns64rns 104

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

OK335xS Ubuntu 12.04.1 版本 Android 开发环境搭建

/******************************************************************************************** * OK335xS Ubuntu 12.04.1 版本 Android 开发环境搭建 * * 声明: * 1. 本人用的虚拟机是 VMwar...

weixin_33941350的博客 128

【摘录】Ubuntu 10.04环境下载&编译Android-2.1_r2源代码

【摘录自】http://blog.youkuaiyun.com/jackyu613/archive/2010/07/31/5778646.aspx前言本文叙述了如何从零开始搭建基于Google官方Android 2.1-r2源码的开发环境,包括如何下载源代码、编译源代码,以及在模拟器中运行编译生成的镜像。文中开发机是基于Ubuntu 10.04的,同样适用于其他版本的Ubuntu。 2. 下载JDK 1...

weixin_30684743的博客 92

Android源码编译调试详解

  Android2.2 源码编译 1、编译环境 Android2.2 + Ubuntu10.04 + JDK1.5 安装必要的软件环境 sudo apt-get install git-core sudo apt-get install gnupg sudo apt-get install flex sudo apt-get install bison sudo apt-get...

雅库无忧 193

Ubuntu 18.04安装openJDK7编译安卓6.0.0_r1

最近在使用AOSP编译安卓6.0.0_r1源码,自己的机器是Ubuntu18.04 TLS,试了网上所有安装openjdk7的教程发现没有一个可以使用的,实属无奈只能自己动手解决这个问题完成了编译,教程如下 1、下载openJDK7 很多人都会卡在这一步,编译AOSP只能使用open JDK不能使用Oracle JDK,在ubuntu18.04上添加opoenjdk7的ppa后用apt insta...

Han的博客 2548

Ubuntu18.04 编译 Android10.0 系统源代码

编译环境 1、Ubuntu18.04 系统 2、三星500G SSD EVO系列 3、内存8G,cpu 4核,I5(8年老本了凑合着用用) 准备工作 1、下载 git sudo apt-get install git 开始遇到的问题,git 下载不了,提示下面的信息 Some packages could not be installed. This may mean that you have...

cczhengv 1万+

Ubuntu 16.04编译Android,make 版本过高导致编译失败的问题

如题,近期在Ubuntu 16.04上编译Android 6.0源码的时候出现报错,记录如下:我的开发环境: Ubuntu 16.04 make 4.0 Android M 源码 大致报错如下:/home/fei/dev/android/source/prada/kernel/drivers/input/touchscreen/focaltech/Makefile:9: *** missing seperator。

u013496707的专栏 7124

ubuntu10.04下编译android1.6_donut

虽然官网有说明,可是自己自己编译还是会遇到很多问题,这是我自己动手实践的流程,一来写在这儿备忘,二来对别人也有帮助。1 添加源后面要安装jdk5,可是ubuntu10.04默认是没有jdk5的源的,需要添加合适的源$sudo gedit /etc/apt/sources.list添加以下代码:deb http://run.hit.edu.cn/ubuntu/ jaunty main restricted universe multiverse  deb-src http://run.hit.edu.cn/u

mayqlzu的专栏 2869

ubuntu 16.04编译android5.1 MTK源码

本身环境已经配置好可以编译android 7.0和android 9.0的,后面有之前的老项目要编译android5.1,碰到的几个问题就做下记录。以下解决方法都是从网络上找到并验证可行。 ---------------------------------------------------- JAVA版本使用open_jdk_7 sudo add-apt-repository ppa:openjdk-r/ppa sudo apt-get update sudo apt-get install openj

淡泊明志,宁静致远 717
上一篇: Burning the bridge: Cisco IOS exploits
下一篇: Zone Labs ZoneAlarm Security Bypass
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值