How-to-locate-CRED

[EXPTECH]__How to locate cred

1.where is creds

creds结构提保存在进程的task_struct结构体中,task_struct结构体比较长,不贴出来了,task_struct结构体定义在/include/linux/sched.h中。

因此要定位creds结构体,就要定位到task_struct结构体,linux内核为每一个进程都分配了一个thread_union,

1
2
3
4
union thread_union {
struct thread_info thread_info;
unsigned long stack[THREAD_SIZE/sizeof(long)];
};

因此,thread_info内存布局如图
task_stack

thread_info结构体的task字段即该进程的task_struct结构体指针

1
2
3
4
5
6
7
8
9
struct thread_info {
unsigned long flags; /* low level flags */
mm_segment_t addr_limit; /* address limit */
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
struct restart_block restart_block;
int preempt_count; /* 0 => preemptable, <0 => bug */
int cpu; /* cpu */
};

thread_info中还有一个比较重要的字段addr_limit,表示该进程能可以访问的内存范围,exp中通常也用修改这个字段获取全部内存的操作权限。
另外,THREAD_SIZE在arm与arm64中size不同,因此在定位thread_info时有一些差异。

  • arm
1
2
3
4
5
6
//define in arch/arm/include/asm/page.h
#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
//define in arch/arm/include/asm/thread_info.h
#define THREAD_SIZE_ORDER 1
#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
  • arm64
1
2
//define in arch/arm64/include/asm/thread_info.h
#define THREAD_SIZE 16384

2.如何查找creds

根据上面的creds位置,通常有两种查找creds的方法,
方法一:
如果获取到sp,就可以反推到thread_info的头部,也就可以找到进程的task_struct结构体。事实上,kernel也是通过这种方式定位thread_info结构体的。

1
2
3
4
5
6
//define in arch/arm(arm64)/include/asm/thread_info.h
static inline struct thread_info *current_thread_info(void)
{
return (struct thread_info *)
(current_stack_pointer & ~(THREAD_SIZE - 1));
}

只要带入对应的THREAD_SIZE即可。简化就是

1
2
thread_addr = sp & 0xFFFFFFFFFFFFC000 //for arm64
thread_addr = sp & 0xFFFFE000 //for arm

然后知道thread_info,task_struct的结构
通过
thread_into->task_struct->cred
即可找到cred

方法二:
如果内核sp没有泄露,就只好遍历task_struct链表了,在task_struct结构体中有一个task字段,这个字段时一个双向链表,系统中运行的所有进程都在这个链表中,通常的方法是先定位idle的task_struct(也就是第一个task_struct,这个task_struct是静态分配的,存在于kernel的data段)。然后从这个task_struct遍历所有task_struct,通过其中的特征字段如comm,查找指定的进程的task_struct

task_list

ref:
Android pxn 绕过技术