What is a 'thunk'?

10:54:00 AM 0 Comments

thunk usually refers to a small piece of code that is called as a function, does some small thing, and then JUMPs to another location (usually a function) instead of returning to its caller. Assuming the JUMP target is a normal function, when it returns, it will return to the thunk's caller.
Thunks can be used to implement lots of useful things efficiently
  • protocol translation -- when calling from code that uses one calling convention to code that uses a different calling convention, a thunk can be used to translate the arguments appropriately. This only works if the return conventions are compatable, but that is often the case
  • virtual function handling -- when calling a virtual function of a multiply-inherited base class in C++, there needs to be a fixup of the this pointer to get it to point to the right place. A thunk can do this.
  • dynamic closures -- when you build a dynamic closure, the closure function needs to be able to get at the context where it was created. A small thunk can be built (usually on the stack) which sets up the context info in some register(s) and then jumps to a static piece of code that implements the closure's function. The thunk here is effectively supplying one or more hidden extra arguments to the function that are not provided by the call site.

Shared libraries and execute permissions

9:17:00 PM 0 Comments

n the few discussions you can find on the web about shared-libraries and execute-permissions, you can find a range of various opinions but not a lot about what goes when you execute a library.
The first thing to consider is how the execute-permission interacts with the dynamic loader. When mapping a library, the dynamic-loader doesn't care about file-permissions; it cares about mapping specific internal parts of the .so. Specifically, it wants to map the PT_LOAD segments as-per the permissions specified by the program-header. A random example:
 $ readelf --segments /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0

Elf file type is DYN (Shared object file)
Entry point 0x77c00
There are 7 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x00000000001b5ea4 0x00000000001b5ea4  R E    200000
  LOAD           0x00000000001b6b60 0x00000000003b6b60 0x00000000003b6b60
                 0x0000000000028dc4 0x000000000002c998  RW     200000
The permissions to load the code and data segments are given the Flags output. Code has execute-permissions, and data has write-permissions. These flags are mapped into flags for the mmap call, which the loader then uses to map the various segments of the file into memory.
So, do you actually need execute-permissions on the underlying file to mmap that segment as executable? No, because you can read it. If I can read it, then I can copy the segment to another area of memory I have already mapped with PROT_EXEC and execute it there anyway.
Googling suggests that some systems do require execute-permissions on a file if you want to directly mmap pages from it with PROT_EXEC (and if you dig into the kernel source, there's an ancient system call uselib that looks like it comes from a.out days, given it talks about loading libraries at fixed addresses, that also wants this). This doesn't sound like a terrible hardening step; I wouldn't be surprised if some hardening patches require it. Maximum compatability and historical-features such as a.out also probably explains why gcc creates shared libraries with execute permissions by default.
Thus, should you feel like it, you can run a shared-library. Something trivial will suffice:
int function(void) {
      return 100;
}
$ gcc -fPIC -shared -o libfoo.so foo.c

$ ./libfoo.so
Segmentation fault
This is a little more interesting (to me anyway) to dig into. At a first pass, why does this even vaguely work? That's easy -- an ELF file is an ELF file, and the kernel is happy to map those PT_LOAD segments in and jump to the entry point for you:
$ readelf --segments ./libfoo.so

Elf file type is DYN (Shared object file)
Entry point 0x570
There are 6 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x000000000000070c 0x000000000000070c  R E    200000
  LOAD           0x0000000000000710 0x0000000000200710 0x0000000000200710
                 0x0000000000000238 0x0000000000000240  RW     200000
What's interesting here is that the shared-library has an entry point (e_entry) at all. ELF defines it as:
This member gives the virtual address to which the system first transfers control, thus starting the process. If the file has no associated entry point, this member holds zero.
First things first, where did that entry point come from? The ld manual tells us that the linker will set the entry point based upon the following hierarchy:
  • the -e entry command-line option;
  • the ENTRY(symbol) command in a linker script;
  • the value of a target specific symbol
  • the address of the first byte of the .text section, if present;
  • The address 0.
We know we're not specifying an entry point. The ENTRY command is interesting; we can check our default-link script to see if that is specified:
$ ld --verbose | grep ENTRY
ENTRY(_start)
Interesting. Obviously we didn't specify a _start; so do we have one? A bit of digging leads to the crt files, for C Run-Time. These are little object files automatically linked in by gcc that actually do the support-work to get a program to the point that main is ready to run.
So, if we go and check out the crt files, one can find a definition of _start in crt1.o
$ nm /usr/lib/x86_64-linux-gnu/crt1.o
crt1.o:
0000000000000000 R _IO_stdin_used
0000000000000000 D __data_start
                 U __libc_csu_fini
                 U __libc_csu_init
                 U __libc_start_main
0000000000000000 T _start
0000000000000000 W data_start
                 U main
But do we have that for our little shared-library? We can get a feel for what gcc is linking in by examining the output of -dumpspecs. Remembering gcc is mostly just a driver that calls out to other things, a``specs`` file is what gcc uses to determine which arguments pass around to various stages of a compile:
$ gcc -dumpspecs
...
*startfile:
%{!shared: %{pg|p|profile:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}}
 crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}
The format isn't really important here (of course you can read about it); but the gist is that various flags, such as -static or -pie get passed different run-time initailisation helpers to link-in. But we can see that if we're creating a shared library we won't be getting crt1.o. We can double-confirm this by checking the output of gcc -v (cut down for clarity).
$ gcc -v -fPIC -shared -o libfoo.so foo.c
Using built-in specs.
 ...
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/collect2 -shared -o libfoo.so
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crti.o
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtbeginS.o
/tmp/ccRpsQU3.o
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtendS.o
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crtn.o
So this takes us further down ld's entry-point logic to pointing to the first bytes of .text, which is where the entry-point comes from. So that solves the riddle of the entry point.
There's one more weird thing you notice when you run the library, which is the faulting address in kern.log:
libfoo.so[8682]: segfault at 1 ip 0000000000000001 sp 00007fffcd63ec48 error 14 in libfoo.so[7f54c51fa000+1000]
The first thing is decoding error; 14 doesn't seem to have any relation to anything. Of course everyone has the Intel 64 Architecture Manual (ormm/fault.c that also mentions the flags) to decode this into 1110 which means "no page found for a user-mode write access with reserved-bits found to be set" (there's another post in all that someday!).
So why did we segfault at 0x1, which is an odd address to turn up? Let's disassemble what actually happens when this starts.
00000000000004a0 <call_gmon_start>:
 4a0:   48 83 ec 08             sub    $0x8,%rsp
 4a4:   48 8b 05 2d 03 20 00    mov    0x20032d(%rip),%rax        # 2007d8 <_dynamic x190="">
 4ab:   48 85 c0                test   %rax,%rax
 4ae:   74 02                   je     4b2 
 4b0:   ff d0                   callq  *%rax
 4b2:   48 83 c4 08             add    $0x8,%rsp
 4b6:   c3                      retq
We're moving something in rax and testing it; if true we call that value, otherwise skip and retq. In this case, objdump is getting a bit confused telling us that 2007d8 is related to _DYNAMIC; in fact we can check the relocations to see it's really the value of __gmon_start__:
$ readelf --relocs ./libfoo.so

Relocation section '.rela.dyn' at offset 0x3f0 contains 4 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000200810  000000000008 R_X86_64_RELATIVE                    0000000000200810
0000002007d8  000200000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
0000002007e0  000300000006 R_X86_64_GLOB_DAT 0000000000000000 _Jv_RegisterClasses + 0
0000002007e8  000400000006 R_X86_64_GLOB_DAT 0000000000000000 __cxa_finalize + 0

Relocation section '.rela.plt' at offset 0x450 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000200808  000400000007 R_X86_64_JUMP_SLO 0000000000000000 __cxa_finalize + 0
Thus call_gmon_start, rather unsurprisingly, checks the value of __gmon_start__ and calls it if it is set. Presumably this is set as part of profiling and called during library initialisation -- but it is clearly not an initialiser by itself. The retq ends up popping a value off the stack and jumping to it, which in this case just happens to be 0x1 -- which we can confirm with gdb by putting a breakpoint on the first text address and examining the stack-pointer:
(gdb) x/2g $rsp
0x7fffffffe7d8:        0x0000000000000000      0x0000000000000001
So that gives us our ultimate failure.
Of course, if you're clever, you can get around this and initalise yourself correctly and actually make your shared-library do something when executed. The canonical example of this is libc.so itself:
$ /lib/x86_64-linux-gnu/libc-2.13.so
GNU C Library (Debian EGLIBC 2.13-37) stable release version 2.13, by Roland McGrath et al.
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
...
You can trace through how this actually does work in the same way as we traced through why the trivial example doesn't work.
If you wondering my opinion on executable-bits for shared-libraries; I would not give them execute permissions. I can't see it does anything but open the door to confusion. However, understanding exactly why the library segfaults the way it does actually ends up being a fun little tour around various parts of the toolchain!

How to run a shared library on Linux

9:09:00 PM 0 Comments

In my prevoius blog I have written how to run the shared libraries on
Open-Solaris.
http://bhushanverma.blogspot.com/2008/06/how-to-run-shared-library-on-open.html
Shared object should have following entries to run:
1. +x permission that is by default is given by the static
linker(program linker) when creating a shared object.
2. Entry point at which the program/shared library is starts to run.
3. Interpreter(Run time linker) that is used to run any shared library
after loaded by kernel part exec().
Entry point at which the program/shared library is starts to run can be
given by passing -Wl,-e entry_point to the linker at command line:
To create .interp section by using GNU gcc, use the follwing line of
code on linux:
const char my_interp[] __attribute__((section(".interp"))) =
"/lib/ld-linux.so.2";
Where /lib/ld-linux.so.2 is the path of interpreter(Run time linker)  in linux.
In open solaris we passed -Wl,-I,/usr/lib/ld.so.1 to the sun linker to
create this section.
I think in gnu linker this option is available but do other things.
Demo on Linux machine:
-------------------------
$ cat func.c
const char my_interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
void bar();

int func() {
    printf("Hacking\n");
    bar();
    exit (0);
}

void bar() {
    printf("Bye...\n");
}
$ gcc -fPIC -o func.so -shared -Wl,-e,func func.c
You can see that foo.so have .interp section and interp program header.
# readelf -l func.so
Elf file type is DYN (Shared object file)
Entry point 0x4dc
There are 7 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x00000034 0x00000034 0x000e0 0x000e0 R E 0x4
INTERP 0x0005a3 0x000005a3 0x000005a3 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x00000000 0x00000000 0x005bc 0x005bc R E 0x1000
LOAD 0x0005bc 0x000015bc 0x000015bc 0x00104 0x0010c RW 0x1000
DYNAMIC 0x0005d4 0x000015d4 0x000015d4 0x000c0 0x000c0 RW 0x4
NOTE 0x000114 0x00000114 0x00000114 0x00024 0x00024 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version
.gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata
.interp .eh_frame
03 .ctors .dtors .jcr .data.rel.ro .dynamic .got .got.plt .bss
04 .dynamic
05 .note.gnu.build-id
06
You can cleary see, func.so have .interp section and INTERP program header.
Now try to run func.so:
$ ./func.so
Hacking
Bye...

我的程序我做主--不改代码让只读数据可写

1:00:00 PM 0 Comments

什么情况下,下面这个foo()  函数会返回一个 "Aello  world" 的指针, 而不会运行报错
char *foo()
{
    char* p = (char*)"Hello world";

    p[0] = 'A';

    return p;
}

(运行环境: linux )
很多公司的笔试题里,都认为这段代码是肯定执行出错的。不过某些时候,还是可以继
续运行的。

========================================================
基于我对ELF的理解,稍稍研究了一下,结果如下:

这个返回出错是因为"Hello world"会被放到.rodata里面。
kinwin@ustc-king:/tmp$ cat tt.c
char * foo(){
    char *a = (char *)"Hello  world\n";
    a[0] = 'A';
    return a;
}

kinwin@ustc-king:/tmp$ cc -c tt.c
kinwin@ustc-king:/tmp$ objdump -d tt.o

tt.o:     file format elf32-i386


Disassembly of section .text:

00000000
   0:   55                      push   p
   1:   89 e5                   mov    %esp,p
   3:   83 ec 10                sub    $0x10,%esp
   6:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(p)
   d:   8b 45 fc                mov    -0x4(p),x
  10:   c6 00 41                movb   $0x41,(x)
  13:   8b 45 fc                mov    -0x4(p),x
  16:   c9                      leave  
  17:   c3                      ret  
这里的"Hello World"会生成一个重定位表项
 kinwin@ustc-king:/tmp$ readelf -r tt.o

Relocation section '.rel.text' at offset 0x31c contains 1 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000009  00000501 R_386_32          00000000   .rodata
链接的时候把这个.rodata中的字符串地址填入那堆0的地方。

产生segment fault的原因就是指针指的是.rodata中的内容,而.rodata的段属性是
ALLOC,不带WRITE和EXECUTE,这样在load的时候生成的vm_area_struct也是只读属性的
,写其中的内容自然会在vm_area_struct那里被捕获,然后被sigsegv了。

要让它可写也是Ok的,最根本的就是让它写的时候对应地址的vm_area_struct属性是可
写的,pte层面应该都是可写的。就有几种办法了
1. loader载入elf文件是根据elf的program header来生成对应的vm_area_struct的,其
中默认是两个,一个可读可执行,一个可读可写,.rodata落在了第一块。
因此,法一, program header table的映射关系让.rodata这个section映射到
program header的可读可写块即可

或者,法二:干脆在链接的时候让各目标文件的.rodata连接到.data这个section来(任
一program header中映射的可读可写区域),而.data load的时候是可读可写的,如:
链接脚本如此写:
 .data           :
    *(.rodata)
    *(.data .data.* .gnu.linkonce.d.*)
kinwin@ustc-king:/tmp$ gcc test.c -Wl,-T,ld.ver -o test.out
kinwin@ustc-king:/tmp$ ./test.out
Aello  world

法三: 提示gcc在生成目标文件的时候不放入.rodata,而是放入.data,不知道gcc有无
这样的选项

法四:以上都为修改elf文件输出,也可以在运行时写只读区域之前,把对应的区域用
mprotect把权限改了

Right-click is slow or weird behavior caused by context menu handlers

6:31:00 PM 1 Comments

Symptoms

  1. When you right-click a file/folder, there may be a huge delay before Windows displays the context menu.
  2. When you try to empty Recycle Bin (from Common Tasks), it opens Quick Finder instead.
  3. When you click Play All in the Music or Videos folder Common Tasks, nothing may happen.
  4. When you select multiple files and right click and open / print nothing happens. Whereas, selecting a single file in explorer and right click and open / print, it works fine.
  5. When you right-click a folder in the Start Menu and choose Open or Explore, nothing may happen. (Whereas, it works fine in Windows Explorer.)
  6. Error message "Windows Explorer has encountered a problem and needs to close. We are sorry for the inconvenience" when you right-click a folder.
  7. Right-click is extremely slow only when the network card is enabled.
  8. When you right-click on a folder and choose Properties, nothing may happen.
  9. Your image editing program does not start when you click the Edit button in Windows Picture and Fax Viewer.
  10. Data Execution Prevention (DEP) error occurs when Windows Explorer or Control Panel is launched.
  11. Nothing happens when you click Slideshow or Print in the Tasks pane in Windows Vista.
  12. Unable to launch applications (mainly Windows Installer shortcuts) from the recent programs list in the Windows Vista Start menu.
  13. Device Manager link in the tasks pane does not work in Windows Vista
  14. When you click "Set up backup" or click "Change settings" in Windows 7 Backup and Restore, nothing happens or the System32 folder opens.

Cause

These problems are caused by a bad context menu handler. A context menu handler is a shell extension handler that adds commands to an existing context menu (Example: cut, copy, paste, print, Scan with Norton etc). A poorly coded context menu handler may be causing any of the above symptoms. As context menu handlers can be added in different areas (file class, folder, allfilesystemobjects, HKCR\* registry keys), it's a difficult task for an end-user to pinpoint which shell extension is causing the problem.

Resolution

This article describes the two methods to identify the problematic shell extension.Method 1 involves direct registry editing, which is for advanced users. Method 2 is user-friendly and suits most users (recommended method)
Method 1 is for advanced users. If you are not confident about dealing with registry, proceed to Method 2.

Method 1

First, isolate the problem. Observe when the problem occurs. While right-clicking a particular file type? While right-clicking Folders? While right-clicking all file types? As said earlier, context menu handlers can load from any of these areas:
Registry KeyDescription
HKCR \*\shellex\contextmenuhandlersFiles
HKCR\AllFileSystemObjects\shellex\ contextmenuhandlersFiles and file folders
HKCR\Folder\shellex\contextmenuhandlersFolders
HKCR\Directory\shellex\contextmenuhandlersFile Folders
HKCR\\shellex\contextmenuhandlersFile class
HKCR\Directory\Background\shellex\ContextMenuHandlersDesktop
If any of the symptoms occur when you deal with a folder, then you may need to inspect the context menu handlers loaded in these areas (AllFileSystemObjects, Folder, Directory). If it's only for a .txt file, inspect the file class of .txt file (HKCR\txtfile). Open Registry Editor and backup the selected branch, delete the context menu handlers one-by-one.

Method 2 - Using ShellExView to determine the Context-menu causing the problem

shellexview.JPG (54542 bytes)ShellExView (by Nir Sofer) is an excellent tool  to view and manage all installed shell extensions. If available, it displays the description, as well as version details, company information, location, file name and more. You can optionally disable/enable any item, which can be very useful to disable an extension, that you don t need or that has been left behind in your right click menu from a previous software install.
Effective usage of ShellExView to resolve right-click problems
Download ShellExView (from nirsoft.net) and run it. It will scan the registry for all the shell extensions. Once the scan is over and the list is displayed, you need to spot the context menu handlers. Sort the results using "Type", so that the context menu handlers are displayed together.
The rule is to disable non-Microsoft context menu handlers *one-by-one* and verify if the problem is solved. If disabling one does not solve the problem, undo the disabled item and disable the next non-Microsoft handler. Do the same until the problem is solved and finally identify the culprit. Scroll right to see the Company Name column in ShellExView.
Even more quicker method is to bisect the list of context menu handlers into two groups, disabling half of the entries at a stretch, rebooting and testing the behavior again. JClarke commented on this article:
You can disable them ...they say "one at a time" and see what effect it has on the problem. I did it a lot quicker by bisecting the list, disabling half of the entries in one fell swoop, rebooting and trying the right click.
It worked, so I knew I just had to narrow it down, just as we used to do with msconfig. Then I kept bisecting the list until it was just a few and did those one at a time. The problem is that you have to reboot between tries to get accurate testing of the results of your disabling. I didn't find logging off to be consistent.

Problems when you right-click an empty area in the Desktop?

If you have a problem when you right-click on a blank area on the Desktop, then you need to inspect the handlers in this registry key. (ShellExView v1.14 and later versions enumerate the items from this location)
HKEY_CLASSES_ROOT \ Directory \ Background  \ shellex \ ContextMenuHandlers
The only handler present by default (in a clean XP installation) is the New handler. If you find any additional sub-keys there, it may have be added by third-party applications. Usually, the software that comes with your graphic card adds entries to the above location. Here is one instance, an article from the Intel Graphics Controller website.
Thanks to Cliff for sending this link:
NOTE:  It's not always the Context menu handler,  but a PropertySheet handler or an Icon Handler may be the culprit sometimes. Some readers have reported that the Property Sheet handler "IIS W3ext Module" was responsible for the folder properties issue (See Case:8 in the Symptoms section above), in a Windows XP Professional system, and that reinstalling IISfrom Add/Remove Windows Components fixed the problem.
In one peculiar case, the system file shimgvw.dll (Shell Image Verbs - {e84fda7c-1d6a-45f6-b725-cb260c236066}) itself causing the problem. In case of system files, try running sfc /scannow to fix the problem.