Обход FS.

Тема в разделе "WASM.UNIX", создана пользователем Mika0x65, 15 апр 2008.

  1. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Мое почтение всем.

    Написал простенький обход дерева файловой системы (для себя) на asm под Gentoo. Столкнулся с необычной ситуацией. Код выглядит так:

    Код (Text):
    1. format ELF
    2.  
    3. extrn printf
    4. extrn chdir
    5. extrn opendir
    6. extrn readdir
    7. extrn telldir
    8. extrn seekdir
    9. extrn closedir
    10. extrn exit
    11. extrn lstat
    12. extrn errno
    13. extrn perror
    14. extrn strcpy
    15. extrn strcmp
    16.  
    17. public main
    18.  
    19. struc stat_b st_dev, pad, st_ino, st_mode, st_nlink, st_uid, st_gid, st_rdev, pad2, st_size, st_blksize, st_blocks, st_atime, st_mtime, st_ctime, pad3
    20. {
    21.     .st_dev     dq st_dev;     /* ID of device containing file */
    22.     .pad        dd pad;        /* fucking padding */
    23.     .st_ino     dd st_ino;     /* inode number */
    24.     .st_mode    dd st_mode;    /* protection */
    25.     .st_nlink   dd st_nlink;   /* number of hard links */
    26.     .st_uid     dd st_uid;     /* user ID of owner */
    27.     .st_gid     dd st_gid;     /* group ID of owner */
    28.     .st_rdev    dq st_rdev;    /* device ID (if special file) */
    29.     .pad2       dd pad2;       /* fucking padding2 */
    30.     .st_size    dd st_size;    /* total size, in bytes */
    31.     .st_blksize dd st_blksize; /* blocksize for filesystem I/O */
    32.     .st_blocks  dd st_blocks;  /* number of blocks allocated */
    33.     .st_atime   dq st_atime;   /* time of last access */
    34.     .st_mtime   dq st_mtime;   /* time of last modification */
    35.     .st_ctime   dq st_ctime;   /* time of last status change */
    36.     .pad3       dq pad3;       /* fuckin fuckin padding3? */
    37. }
    38.  
    39.  
    40. NAME_MAX = 0x100
    41. S_IFDIR  = 0x4000   ;directory
    42. S_IFMT   = 0xF000   ;mask
    43.  
    44. main:
    45.  mov eax, [esp + 0x8]
    46.  mov edx, [eax]
    47.  mov [prog], edx
    48.  mov eax, [eax + 0x4]
    49.  
    50.  push eax
    51.  call parse_dir
    52.  
    53.  xor eax, eax
    54.  ret
    55.  
    56. err:
    57.  push dword [esp + 0x4]
    58.  call perror
    59.  call exit
    60.  
    61. warn:
    62.  push dword [esp + 0x4]
    63.  call perror
    64.  add esp, 0x4
    65.  ret 0x4
    66.  
    67. parse_dir:
    68.  sub esp, 0x4
    69.  push dword [esp + 0x8]
    70.  call chdir
    71.  add esp, 0x4
    72.  or eax, eax
    73.  jz @f
    74.  push chdr
    75.  call warn
    76.  jmp .locret
    77. @@:
    78.  
    79.  push dot
    80.  call opendir
    81.  add esp, 0x4
    82.  or eax, eax
    83.  jnz @f
    84.  push opndr
    85.  call warn
    86.  jmp .chdir
    87. @@:
    88.  mov [esp], eax
    89.  
    90. .l00p:
    91.  push dword [esp]
    92.  call readdir
    93.  add esp, 0x4
    94.  or eax, eax
    95.  jnz @f
    96.  cmp dword [errno], 0x0
    97.  jz .closedir
    98.  push rddr
    99.  call warn
    100.  jmp .closedir
    101. @@:
    102.  lea ebx, [eax + 0xB]
    103.  push ebx
    104.  push dot
    105.  call strcmp
    106.  add esp, 0x8
    107.  or eax, eax
    108.  jz .l00p
    109.  push ebx
    110.  push dotdot
    111.  call strcmp
    112.  add esp, 0x8
    113.  or eax, eax
    114.  jz .l00p
    115.  
    116.  push stat_buff
    117.  push ebx
    118.  call lstat
    119.  add esp, 0x8
    120.  or eax, eax
    121.  jz @f
    122.  push stt
    123.  call warn
    124.  jmp .closedir
    125. @@:
    126.  
    127.  mov eax, [stat_buff.st_mode]
    128.  and eax, S_IFMT
    129.  cmp eax, S_IFDIR
    130.  jnz .nextf
    131.  
    132.  push ebx
    133.  push name_buff
    134.  call strcpy
    135.  add esp, 0x8
    136.  
    137.  push dword [esp]
    138.  call telldir
    139.  add esp, 0x4
    140.  mov ebx, eax
    141.  
    142.  push dword [esp]
    143.  call closedir
    144.  add esp, 0x4
    145.  mov [esp], ebx
    146.  
    147.  push name_buff
    148.  call parse_dir
    149.  
    150.  push dot
    151.  call opendir
    152.  add esp, 0x4
    153.  mov ebx, eax
    154.  
    155.  push dword [esp]
    156.  push ebx
    157.  call seekdir
    158.  add esp, 0x8
    159.  
    160.  mov [esp], ebx
    161. .nextf:
    162.  jmp .l00p
    163.  
    164. .closedir:
    165.  push dword [esp]
    166.  call closedir
    167.  add esp, 0x4
    168. .chdir:
    169.  push dotdot
    170.  call chdir
    171.  add esp, 0x4
    172. .locret:
    173.  add esp, 0x4
    174.  ret 0x4
    175.  
    176. prog: dd ?
    177. name_buff: db NAME_MAX dup 0x0
    178. stat_buff stat_b 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    179. dot: db '.', 0x0
    180. dotdot: db '..', 0x0
    181. opndr: db 'opendir: ', 0x0
    182. rddr: db 'readdir: ', 0x0
    183. stt: db 'stat: ', 0x0
    184. chdr: db 'chdir: ', 0x0
    Но если натравить исполняемый, например, на такую директорию

    mkdir t && cd t && mkdir t && chmod 000 t

    То после выхода из вложения ф-ии, где chdir сделать не удалось, последующая операция readdir вернет 'Illegal seek' -- ошибку, котрой даже нет в man 3 readdir. Отчего такое может происходить?

    Заранее благодарен.
     
  2. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    seekdir() внутри readdir() возвращает ошибку, а ты проверяешь errno, который установил seekdir().
     
  3. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    ну происходит то понятно отчего
    вызов seekdir() перед .nextf устанавливает неправильное смещение (а т. к seekdir() не устанавливает errno и ничего не возвращает, мы ошибку определить не можем)
    далее, естественно, вызов readdir() обламывается
    остается выяснить, почему значение смещения неправильное
     
  4. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    seekdir() не устанавливает errno
    оно изменяет поле d_off структуры dirent и все
     
  5. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    n0name
    Странно, у меня ничего подобного в мане не сказано:

    Но в любом случае, когда я делаю почти то же самое -- т.е. просто открываю директорию, читаю 3 файла ("." и "..", "t"), сохраняю позицию, закрываю, открываю, восстанавливаю позицию и читаю -- readdir возвращает NULL, а в errno лежит success. Как и должно быть...
     
  6. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    rei3er
    В том-то и дело -- я посмотрел в gdb (и printf'ами выводил) -- то, что получено из telldir передается в seekdir. Не может же telldir врать. Я уж думал, что тип off_t занимает 8 байт, но sizeof(off_t) показывает 4.
     
  7. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Кстати, если в директории (первой t) есть файлы, помимо вложенной директории t, к которой нет доступа, то они нормально возвращаются ф-ией readdir. Когда она доходит до конца директории, то завершается с Illegal seek.
     
  8. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    Mika0x65
    а если попробовать вместо вызова seekdir() вызывать в цикле readdir() + telldir() до момента, пока значение, возвращаемое telldir() не станет равно сохраненному
    Код (Text):
    1. ...
    2. @@:
    3.  push ebx
    4.  call telldir
    5.  add esp, 4
    6.  cmp eax, dword [esp]
    7.  jz @F
    8.  push ebx
    9.  call readdir
    10.  add esp, 4
    11.  jmp @B
    12. @@:
    13. ...
    какой результат?
     
  9. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    rei3er
    Сделал так. Результат тот же. У меня было подозрение -- не порчу ли где-нибудь структуру struct DIR. Но, вроде, нигде гнилых указателей нет.
     
  10. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    Mika0x65
    сделай так
    Код (Text):
    1. parse_dir:
    2.  sub esp, 0x4
    3.  push dword [esp + 0x8]
    4.  call chdir
    5.  add esp, 0x4
    6.  or eax, eax
    7.  jz @f
    8.  push chdr
    9.  call warn
    10.  mov dword [errno], 0 ; обнуляем errno
    11.  jmp .locret
    12. @@:
     
  11. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    rei3er
    Спасибо, помогло! Только непонятно, errno же должна устанавливаться последующим (успешным) вызовом readdir?
     
  12. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    Mika0x65
    если функция завершается успешно, errno не обнуляется
    да и зачем ей обнуляться, если нет ошибки?
    кстати, какая у тебя версия glibc?
    по тому, как идет обращение к errno, можно предположить, что довольно старая ;)
     
  13. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    rei3er
    Точно. Невнимательно man 3 errno прочитал :dntknw:.

    Насчет вресии точно не знаю, т.к. машину собирал не я (удаленный сервер).
    ls -l /lib/libc*
    -rwxr-xr-x 1 root root 1216736 Mar 19 2006 /lib/libc-2.3.5.so
    lrwxrwxrwx 1 root root 13 Feb 8 2007 /lib/libc.so.6 -> libc-2.3.5.so