2015腾讯暑期实习生面试
好吧,其实我是冒充2016届毕业生投的简历,但是简历上没写我是2017届毕业。等待面试的时候还是很紧张的,毕竟是人生中第一次参加这种大型招聘会。但是等真正进去面试的时候整个人反而平静下来了,聊了能有一个多小时吧。其实在面试之前就有收到过电话面试,不过当时毫无准备,答的也挺糟的,在线笔试我自己就感觉挺糟,一直就觉得没有通过,笔试的范围涉及挺广的,Web,Android,Ios和Linux 都有,windows的内容应该是相对来说最少的了。问面试官才知道自己笔试成绩21分,总分好像是100分。但是很感谢面试官还是给了我这次面试的机会。
可能是我看起来确实太小了,而且简历上也没有写毕业时间,第一个问题就是,你是2016届毕业吗?回答的不是,只是为了来感受一下大型招聘会的感觉,毕竟第一次参加这种大型招聘会,积累下经验。感觉面试官人挺好的,没有立即结束这次面试,而是说晚上和HR那边沟通一下,看是不是一定卡毕业时间。然后才算开始真正的面试吧!后来面试官第二天给我发消息说感觉我很好,但是HR那边说人员很充足,只收2016届,然后就没有然后了。
问的问题也不算很难,可能一面吧,问的都是很基础的一些问题。答的感觉还行。
1. C++ 的虚拟多态的汇编层的实现
虚函数表和虚表指针 推荐《C++反汇编与逆向技术分析揭秘》一书,从汇编层来看待C++ 的运行机制
2. 什么情况下父类和子类的虚函数都会执行
如果子类对于父类的虚函数没有自己实现,则子类对象的虚函数表中依然存放的是父类虚函数的地址,
如果子类自己重新实现了父类的虚函数,则存放自己的虚函数地址
4. 一个对象怎么判断是子类对象还是父类对象
C++提供各种操作符,可进行运行时检测,typeid()确定和dynamic_cast检查一个对象的数据类型。RTTI 是编译器实现的细节。
3. __stdcall 和 __cdecl 的区别,为什么会有这两种调用方式 举了CreateProcess() 和 printf() 来对比
不仅仅从清栈的角度,还有参数的角度,__cdecl一般用于可变参数
4.PE文件RVA 和 offset 的转化
5.CreateProcess() 的底层实现
6.ntdll.dll中调用sysenter 的是哪一个函数
面试的前两天刚在看《软件调试》,然后还特意用ida看过这个函数,面试当时却忘了,可能是有点紧张吧。
ShareUserData!CallSystemStub
7.int 2e 和 sysenter 的区别
《软件调试》讲的很清楚,我记得不是很清了,只能记住最主要的
int 2e 是中断,中断服务例程就是KiSystemService(),KiSystemService在内核空间,会先做用户态转向内核态的工作,包括:
1.检查权限,检查源位置和目标位置所在的代码段的权限,核实是否可以转移;
2. 准备内核态使用的栈,为保证内核安全,所有线程在内核态执行都必须使用内核态空间的栈,一般是8Kb或者12KB :
然后转向SSDT表,复制参数到内核栈,调用指定的SSDT函数,操作结束返回KiSystemService将结果复制到线程用户栈,iret返回到ntdll中的函数。
sysenter 直接转向KiFastCallEntry() 寄存器传参,然后转向KiSystemService
而对于Zw和Nt系列函数的区别,在ntdll中两者是一样的,但在内核中,例如NtReadFile是SSDT表中调用,ZwReadFile时通过KiSystemService来分发处理,调用 NtReadFile的。
发起系统调用 入口内核例程 返回指令 返回内核例程
int 2e KiSystemService iret KiSystemCallExit
sysenter(Intel) KiFastCallEntry SYSEXIT KiSytemcallExit2
syscall (AMD) KiFastCallEntry SYSRETURN KiSystemCallExit3
8.对于ring0 SSDT 的inlinehook 的检测,我只检测了函数内存中的前10个字节,如果函数时在中间或者末尾被inlinehook,怎么检测?
这个回答的不是太好,现在想到的一个解决办法是通过符号表来解析一个函数的大小。