本文为看雪论坛优秀文章
看雪论坛作者ID:珍惜Any
1
前言
2
netlink简介
3
netlink特点
(1)支持全双工、异步通信;
4
netlink优点
5
如何通过netlink获取网卡信息?
android 是如何通过netlink获取网卡地址的?
6
getifaddrs方法介绍
//传入对应的结构体指针
int getifaddrs(ifaddrs** out) {
// We construct the result directly into `out`, so terminate the list.
*out = nullptr;
// Open the netlink socket and ask for all the links and addresses.
NetlinkConnection nc;
//判断get addresses 和 get link是否打开成功,返回成功则返回0
bool okay = nc.SendRequest(RTM_GETLINK) && nc.ReadResponses(__getifaddrs_callback, out) &&
nc.SendRequest(RTM_GETADDR) && nc.ReadResponses(__getifaddrs_callback, out);
if (!okay) {
out = nullptr;
freeifaddrs(*out);
// Ensure that callers crash if they forget to check for success.
*out = nullptr;
return -1;
}
return 0;
}
/**
* @param type 发送参数的类型,具体获取的内容参考
* @see rtnetlink.h
* @return
*/
bool NetlinkConnection::SendRequest(int type) {
// Rather than force all callers to check for the unlikely event of being
// unable to allocate 8KiB, check here.
// NetlinkConnection构造方法 的时候生成的8kb的data内存
if (data_ == nullptr) return false;
// Did we open a netlink socket yet?
if (fd_ == -1) {
//尝试建立socket netlink 链接
fd_ = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
if (fd_ == -1) return false;
}
// Construct and send the message.
// 构造要发送的消息
struct NetlinkMessage {
nlmsghdr hdr;
rtgenmsg msg;
} request;
memset(&request, 0, sizeof(request));
request.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
request.hdr.nlmsg_type = type;
request.hdr.nlmsg_len = sizeof(request);
// All families
request.msg.rtgen_family = AF_UNSPEC;
//使用socket数据发送
return (TEMP_FAILURE_RETRY(send(fd_, &request, sizeof(request), 0)) == sizeof(request));
}
/*
* 获取socket的返回结果
*/
bool NetlinkConnection::ReadResponses(void callback(void*, nlmsghdr*), void* context) {
// Read through all the responses, handing interesting ones to the callback.
ssize_t bytes_read;
while ((bytes_read = TEMP_FAILURE_RETRY(recv(fd_, data_, size_, 0))) > 0) {
//将拿到的data数据进行赋值
auto* hdr = reinterpret_cast<nlmsghdr*>(data_);
for (; NLMSG_OK(hdr, static_cast<size_t>(bytes_read)); hdr = NLMSG_NEXT(hdr, bytes_read)) {
//判断是否读取结束,否则读取callback
if (hdr->nlmsg_type == NLMSG_DONE) return true;
if (hdr->nlmsg_type == NLMSG_ERROR) {
auto* err = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(hdr));
errno = (hdr->nlmsg_len >= NLMSG_LENGTH(sizeof(nlmsgerr))) ? -err->error : EIO;
return false;
}
//处理具体逻辑
callback(context, hdr);
}
}
// We only get here if recv fails before we see a NLMSG_DONE.
return false;
}
使用流程:通过遍历拿到我们需要的内容,输出即可。
int listmacaddrs(void) {
struct ifaddrs *ifap, *ifaptr;
if (myGetifaddrs(&ifap) == 0) {
for (ifaptr = ifap; ifaptr != NULL; ifaptr = (ifaptr)->ifa_next) {
char macp[INET6_ADDRSTRLEN];
if(ifaptr->ifa_addr!= nullptr) {
if (((ifaptr)->ifa_addr)->sa_family == AF_PACKET) {
auto *sockadd = (struct sockaddr_ll *) (ifaptr->ifa_addr);
int i;
int len = 0;
for (i = 0; i < 6; i++) {
len += sprintf(macp + len, "%02X%s", sockadd->sll_addr[i],( i < 5 ? ":" : ""));
}
//LOGE("%s %s ",(ifaptr)->ifa_name,macp)
if(strcmp(ifaptr->ifa_name,"wlan0")== 0){
LOGE("%s %s ",(ifaptr)->ifa_name,macp)
freeifaddrs(ifap);
return 1;
}
}
}
}
freeifaddrs(ifap);
return 0;
} else {
return 0;
}
}
SVC内联安全封装:在接受消息的时候android源码是采用recv去接受的消息
/*
* 获取socket的返回结果
*/
bool NetlinkConnection::ReadResponses(void callback(void*, nlmsghdr*), void* out) {
// Read through all the responses, handing interesting ones to the callback.
ssize_t bytes_read;
// while ((bytes_read = TEMP_FAILURE_RETRY(recv(fd_, data_, size_, 0))) > 0) {
// while ((bytes_read = TEMP_FAILURE_RETRY(recvfrom(fd_, data_, size_, 0 ,NULL,0))) > 0) {
while ((bytes_read = TEMP_FAILURE_RETRY(raw_syscall(__NR_recvfrom,fd_, data_, size_, 0, NULL,0))) > 0) {
auto* hdr = reinterpret_cast<nlmsghdr*>(data_);
for (; NLMSG_OK(hdr, static_cast<size_t>(bytes_read)); hdr = NLMSG_NEXT(hdr, bytes_read)) {
if (hdr->nlmsg_type == NLMSG_DONE) return true;
if (hdr->nlmsg_type == NLMSG_ERROR) {
auto* err = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(hdr));
errno = (hdr->nlmsg_len >= NLMSG_LENGTH(sizeof(nlmsgerr))) ? -err->error : EIO;
return false;
}
callback(out, hdr);
}
}
// We only get here if recv fails before we see a NLMSG_DONE.
return false;
}
extern "C" {
__inline__ __attribute__((always_inline)) long raw_syscall(long __number, ...);
}
.text
raw_syscall
raw_syscall,%function
raw_syscall:
MOV R12, SP
STMFD SP!, {R4-R7}
MOV R7, R0
MOV R0, R1
MOV R1, R2
MOV R2, R3
LDMIA R12, {R3-R6}
SVC 0
LDMFD SP!, {R4-R7}
mov pc, lr
.text
raw_syscall
raw_syscall,@function
raw_syscall:
MOV X8, X0
MOV X0, X1
MOV X1, X2
MOV X2, X3
MOV X3, X4
MOV X4, X5
MOV X5, X6
SVC 0
RET
while ((bytes_read = TEMP_FAILURE_RETRY(raw_syscall(__NR_recv,fd_, data_, size_, 0, NULL,0))) > 0) {
auto* hdr = reinterpret_cast<nlmsghdr*>(data_);
for (; NLMSG_OK(hdr, static_cast<size_t>(bytes_read)); hdr = NLMSG_NEXT(hdr, bytes_read)) {
//判断是否读取结束,否则读取callback
if (hdr->nlmsg_type == NLMSG_DONE) return true;
if (hdr->nlmsg_type == NLMSG_ERROR) {
auto* err = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(hdr));
errno = (hdr->nlmsg_len >= NLMSG_LENGTH(sizeof(nlmsgerr))) ? -err->error : EIO;
return false;
}
//处理具体逻辑
callback(out, hdr);
}
}
// We only get here if recv fails before we see a NLMSG_DONE.
return false;
}
2022-03-02 21:47:13.753 5867-5867/? A/DEBUG: Build fingerprint: 'Xiaomi/cmi/cmi:11/RKQ1.200826.002/21.11.3:user/release-keys'
2022-03-02 21:47:13.753 5867-5867/? A/DEBUG: Revision: '0'
2022-03-02 21:47:13.753 5867-5867/? A/DEBUG: ABI: 'arm'
2022-03-02 21:47:13.756 5867-5867/? A/DEBUG: Timestamp: 2022-03-02 21:47:13+0800
2022-03-02 21:47:13.756 5867-5867/? A/DEBUG: pid: 5773, tid: 5773, name: example.jnihook com.example.jnihook <<<
2022-03-02 21:47:13.756 5867-5867/? A/DEBUG: uid: 10019
2022-03-02 21:47:13.756 5867-5867/? A/DEBUG: signal 31 (SIGSYS), code 1 (SYS_SECCOMP), fault addr --------
2022-03-02 21:47:13.756 5867-5867/? A/DEBUG: Cause: seccomp prevented call to disallowed arm system call 291
2022-03-02 21:47:13.756 5867-5867/? A/DEBUG: r0 0000004c r1 da3ea000 r2 00002000 r3 00000000
2022-03-02 21:47:13.756 5867-5867/? A/DEBUG: r4 00000000 r5 00000000 r6 00000000 r7 00000123
2022-03-02 21:47:13.756 5867-5867/? A/DEBUG: r8 00000000 r9 f1ff2e00 r10 ffeedb20 r11 f1ff2e00
2022-03-02 21:47:13.756 5867-5867/? A/DEBUG: ip ffeed9f8 sp ffeed9e8 lr c4459b03 pc c445a3a4
2022-03-02 21:47:13.756 5867-5867/? A/DEBUG: backtrace:
2022-03-02 21:47:13.757 5867-5867/? A/DEBUG: #00 pc 0000c3a4 /data/app/~~O88Sqqnxjf7EjHid_THMIA==/com.example.jnihook-j2EVKCAjF3Cpu3p_RLym8A==/lib/arm/libhelloword.so (BuildId: 95d05421436486cc260cc32f813488b04b882b78)
....
7
secomp简介
read() write() exit() rt_sigreturn
通过下面方式进行设置:
seccomp(SECCOMP_SET_MODE_STRICT)
prctl (PR_SET_SECCOMP, SECCOMP_MODE_STRICT)。
strict
int main(int argc, char **argv)
{
int output = open(“output.txt”, O_WRONLY);
const char *val = “test”;
//通过prctl函数设置seccomp的模式为strict
printf(“Calling prctl() to set seccomp strict mode…n”);
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
printf(“Writing to an already open file…n”);
//尝试写入
write(output, val, strlen(val)+1);
printf(“Trying to open file for reading…n”);
//设置完毕seccomp以后再次尝试open (因为设置了secomp的模式是strict,所以这行代码直接sign -9 信号)
int input = open(“output.txt”, O_RDONLY);
printf(“You will not see this message — the process will be killed firstn”);
}
filter(BPF)
__BIONIC_FORTIFY_INLINE
ssize_t recv(int socket, void* const buf __pass_object_size0, size_t len, int flags)
__overloadable
__clang_error_if(__bos_unevaluated_lt(__bos0(buf), len),
"'recv' called with size bigger than buffer") {
return recvfrom(socket, buf, len, flags, NULL, 0);
}
bool NetlinkConnection::ReadResponses(void callback(void*, nlmsghdr*), void* out) {
// Read through all the responses, handing interesting ones to the callback.
ssize_t bytes_read;
while ((bytes_read = TEMP_FAILURE_RETRY(raw_syscall(__NR_recvfrom,fd_, data_, size_, 0, NULL,0))) > 0) {
auto* hdr = reinterpret_cast<nlmsghdr*>(data_);
for (; NLMSG_OK(hdr, static_cast<size_t>(bytes_read)); hdr = NLMSG_NEXT(hdr, bytes_read)) {
if (hdr->nlmsg_type == NLMSG_DONE) return true;
if (hdr->nlmsg_type == NLMSG_ERROR) {
auto* err = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(hdr));
errno = (hdr->nlmsg_len >= NLMSG_LENGTH(sizeof(nlmsgerr))) ? -err->error : EIO;
return false;
}
//处理具体逻辑
callback(out, hdr);
}
}
// We only get here if recv fails before we see a NLMSG_DONE.
return false;
}
2022-03-02 22:05:53.790 11145-11145/com.example.jnihook E/Netlink: wlan0 A4:4B:D5:0B:51:57
git地址:https://github.com/w296488320/getMacForNetlink
看雪ID:珍惜Any
https://bbs.pediy.com/user-home-819934.htm
# 往期推荐
3.通过DWARF Expression将代码隐藏在栈展开过程中
4.x86-页式管理
球分享
球点赞
球在看
点击“阅读原文”,了解更多!
原文始发于微信公众号(看雪学苑):Android netlink&svc 获取 Mac方法深入分析