2022年3月26日 星期六

GDB - jump - 17.2 Continuing at a Different Address


jump顧名思義就是跳到某一行開始執行, 而且是會立刻執行直到遇到breakpoint. 因為jump並不會對stack, memory, 或register有任何改變(除了PC/program counter), 也因此jump的範圍需要在同一個function內部, 避免crash.
你也可以用set $pc=<execute_address> + "continue", "next", "step"替代
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...done.
(gdb) set listsize unlimited
(gdb) list
1       #include <stdio.h>
2
3       static void possible_crash_1(void)
4       {
5           printf("%s(#%d)\n", __FUNCTION__, __LINE__);
6       }
7
8       static void possible_crash_2(void)
9       {
10          printf("%s(#%d)\n", __FUNCTION__, __LINE__);
11      }
12
13      static void possible_crash_3(void)
14      {
15          printf("%s(#%d)\n", __FUNCTION__, __LINE__);
16      }
17
18      int main(int argc, char *argv[])
19      {
20          possible_crash_1();
21
22          possible_crash_2();
23
24          possible_crash_3();
25
26          return 0;
27      }
28
(gdb) b main
Breakpoint 1 at 0x400576: file jump.c, line 20.
(gdb) run
Starting program: /build/brook/a.out

Breakpoint 1, main (argc=1, argv=0x7fffffffe4e8) at jump.c:20
20          possible_crash_1();
(gdb) j 22
Continuing at 0x40057b.
possible_crash_2(#10)
possible_crash_3(#15)
[Inferior 1 (process 9816) exited normally]
(gdb) run
Starting program: /build/brook/a.out

Breakpoint 1, main (argc=1, argv=0x7fffffffe4e8) at jump.c:20
20          possible_crash_1();
(gdb) set $pc=0x40057b
(gdb) n
possible_crash_2(#10)
24          possible_crash_3();
(gdb) n
possible_crash_3(#15)
26          return 0;



  • 參考資料:
      https://sourceware.org/gdb/download/onlinedocs/gdb/Jumping.html#Jumping, 17.2 Continuing at a Different Address



  • 2022年2月27日 星期日

    lighttpd & CGI note


    CGIC提供了簡單的API, 存取那一些CGIC已經幫你parse好的資料,比如: cgiRequestMethod, cgiRemoteAddr, cgiScriptName, 以及POST/GET資料等等, header的資料可以透過environ讀取
    可以透過cgiFormEntries(char ***result)抓key, 再透過cgiFormString(char *name, char *result, int max)取得資料,
    #include <stdio.h>
    #include <cgic.h>
    extern char **environ;
    
    int cgiMain() {
      char **array, **arrayStep, val[64];
      fprintf(cgiOut, "cgiRequestMethod:%s\n", cgiRequestMethod);
      fprintf(cgiOut, "cgiRemoteAddr:%s\n", cgiRemoteAddr);
      fprintf(cgiOut, "cgiScriptName:%s\n", cgiScriptName);
      fprintf(cgiOut, "cgiContentType:%s\n", cgiContentType);
      fprintf(cgiOut, "used for GET, cgiQueryString:%s\n", cgiQueryString);
    
      if (cgiFormEntries(&array) == cgiFormSuccess) {
          for (arrayStep = array; *arrayStep; arrayStep++) {
              fprintf(cgiOut, "get post by cgiFormEntries():%s\n", *arrayStep);
              cgiFormString(*arrayStep, val, sizeof(val));
              fprintf(cgiOut, "val:%s\n", val);
          }
      }
      for (array = environ; *array; array++) {
          fprintf(cgiOut, "get from env:%s\n", *array);
      }
    
      return 0;
    }
    


    GET

    [brook@:/var/www/html]$ curl -H "xhead: 123" --noproxy 127.0.0.1 http://127.0.0.1/cgic.cgi?xquery=123
    cgiRequestMethod:GET
    cgiRemoteAddr:127.0.0.1
    cgiScriptName:/cgic.cgi
    cgiContentType:
    used for GET, cgiQueryString:xquery=123
    get post by cgiFormEntries():xquery
    val:123
    get from env:CONTENT_LENGTH=0
    get from env:QUERY_STRING=xquery=123
    get from env:REQUEST_URI=/cgic.cgi?xquery=123
    get from env:REDIRECT_STATUS=200
    get from env:SCRIPT_NAME=/cgic.cgi
    get from env:SCRIPT_FILENAME=/var/www/html/cgic.cgi
    get from env:DOCUMENT_ROOT=/var/www/html
    get from env:REQUEST_METHOD=GET
    get from env:SERVER_PROTOCOL=HTTP/1.1
    get from env:SERVER_SOFTWARE=lighttpd/1.4.64
    get from env:GATEWAY_INTERFACE=CGI/1.1
    get from env:REQUEST_SCHEME=http
    get from env:SERVER_PORT=80
    get from env:SERVER_ADDR=127.0.0.1
    get from env:SERVER_NAME=127.0.0.1
    get from env:REMOTE_ADDR=127.0.0.1
    get from env:REMOTE_PORT=52894
    get from env:HTTP_HOST=127.0.0.1
    get from env:HTTP_USER_AGENT=curl/7.47.0
    get from env:HTTP_ACCEPT=*/*
    get from env:HTTP_XHEAD=123
    



    POST

    [brook@:/var/www/html]$ curl -H "xhead: 123" --noproxy 127.0.0.1 -X POST -d 'post1=p1&post2=p2' http://127.0.0.1/cgic.cgi?xquery=123
    cgiRequestMethod:POST
    cgiRemoteAddr:127.0.0.1
    cgiScriptName:/cgic.cgi
    cgiContentType:application/x-www-form-urlencoded
    used for GET, cgiQueryString:xquery=123
    get post by cgiFormEntries():post1
    val:p1
    get post by cgiFormEntries():post2
    val:p2
    get from env:CONTENT_LENGTH=17
    get from env:QUERY_STRING=xquery=123
    get from env:REQUEST_URI=/cgic.cgi?xquery=123
    get from env:REDIRECT_STATUS=200
    get from env:SCRIPT_NAME=/cgic.cgi
    get from env:SCRIPT_FILENAME=/var/www/html/cgic.cgi
    get from env:DOCUMENT_ROOT=/var/www/html
    get from env:REQUEST_METHOD=POST
    get from env:SERVER_PROTOCOL=HTTP/1.1
    get from env:SERVER_SOFTWARE=lighttpd/1.4.64
    get from env:GATEWAY_INTERFACE=CGI/1.1
    get from env:REQUEST_SCHEME=http
    get from env:SERVER_PORT=80
    get from env:SERVER_ADDR=127.0.0.1
    get from env:SERVER_NAME=127.0.0.1
    get from env:REMOTE_ADDR=127.0.0.1
    get from env:REMOTE_PORT=52904
    get from env:HTTP_HOST=127.0.0.1
    get from env:HTTP_USER_AGENT=curl/7.47.0
    get from env:HTTP_ACCEPT=*/*
    get from env:HTTP_XHEAD=123
    get from env:HTTP_CONTENT_LENGTH=17
    get from env:CONTENT_TYPE=application/x-www-form-urlencoded
    



    header的部分會被轉成HTTP_VAR=val方式存在environment中, 相關的code如下,
    http_cgi_encode_varname()
    {
      if (is_http_header) {
        memcpy(p, "HTTP_", 5);
        j = 5; /* "HTTP_" */
      }
      /* uppercase alpha */
      ...
    }
    
    http_cgi_headers()
    {
      ...
      for (n = 0; n < r->rqst_headers.used; n++) {
        http_cgi_encode_varname(tb, BUF_PTR_LEN(&ds->key), 1);
      }
      ...
    }
    
    cgi_create_env()
    {
      /* create environment */
      http_cgi_headers(r, &opts, cgi_env_add, env);
      ...
      pid_t pid = (dfd >= 0) ? fdevent_fork_execve(args[0], args, envp,
        to_cgi_fds[0], from_cgi_fds[1], serrh_fd, dfd): -1;
      ...
    }
    
    mod_cgi_handle_subrequest()
    {
      ...
      cgi_create_env();
      ...
    }
    


    2022年1月1日 星期六

    A pattern for command table


    我們常常會需要比對字串/指令後, 執行對應的function, 常見的就是用for loop把command table比對過一次, 但是如果command table大, 效率就不好, 可以用qsort()+bsearch()做binary search以提升效率.

    #include <stdio.h> #include <string.h> typedef void (*cmd_fp)(char *cmd);
    /* * command function */ void hello(char *cmd) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); }
    /* * command function */ void world(char *cmd) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); } /* The structure for command entry */ struct cmd_ent { char const * cmd; cmd_fp fp; } /* Command table - a command array */ cmd_tab[] = { {"hello", hello}, {"world", world}, }; #define AR_SZ(a) (sizeof(a)/sizeof(a[0])) int main(int argc, char *argv[]) { char cmd[64]; int i; while(fgets(cmd, sizeof(cmd) - 1, stdin)) { cmd[strlen(cmd) - 1] = 0; for (i = 0; i < AR_SZ(cmd_tab); i++) { if (strcmp(cmd, cmd_tab[i].cmd) == 0) { cmd_tab[i].fp(cmd); break; } } if (i == AR_SZ(cmd_tab)) { printf("cmd not found\n"); } } }


    qsort() + bsearch() version
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    typedef void (*cmd_fp)(char *cmd);
    
    /* * command function */ void hello(char *cmd) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); }
    /* * command function */ static void world(char *cmd) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); }
    /* The structure for command entry */ struct cmd_ent { char const * cmd; cmd_fp fp; };
    /* Command table that is qsort() + bsearch() version */ static struct cmd_tab { int sz; // total htab size int count; // how many comand entry stored in htab. struct cmd_ent *htab; } cmd_tab; /* * increas htab. it will be invoked once htab is full. */ static struct cmd_ent * realloc_htab_and_copy(int new_sz, struct cmd_ent *otab, int num) { struct cmd_ent *ntab; ntab = (struct cmd_ent *) malloc(sizeof(struct cmd_ent) * new_sz); memset(ntab, 0, sizeof(struct cmd_ent) * new_sz); if (num) { memcpy(ntab, otab, sizeof(struct cmd_ent) * num); free(otab); } return ntab; } /* compare function is used for qsort()/sorting or bsearch()/searching */ static int compmi(const void *v1, const void *v2) { struct cmd_ent* e1 = (struct cmd_ent*) v1; struct cmd_ent* e2 = (struct cmd_ent*) v2; return strcmp(e1->cmd, e2->cmd); } /* used for registering a new "cmd"/"fp" into comand table */ static void reg_cmd(char *cmd, cmd_fp fp) { if (cmd_tab.sz == cmd_tab.count) { cmd_tab.sz = (cmd_tab.sz + 16) * 2; cmd_tab.htab = realloc_htab_and_copy(cmd_tab.sz, cmd_tab.htab, cmd_tab.count); } cmd_tab.htab[cmd_tab.count].cmd = cmd; cmd_tab.htab[cmd_tab.count].fp = fp; cmd_tab.count++; qsort(cmd_tab.htab, cmd_tab.count, sizeof(struct cmd_ent), compmi); } /* an example to register two commands into command table */ static void reg_cmds(void) { reg_cmd("hello", hello); reg_cmd("world", world); } int main(int argc, char *argv[]) { char cmd[64]; struct cmd_ent key, *res; int i; reg_cmds(); while(fgets(cmd, sizeof(cmd) - 1, stdin)) { /* main body for command searching */ cmd[strlen(cmd) - 1] = 0; key.cmd = cmd; res = bsearch(&key, cmd_tab.htab, cmd_tab.count, sizeof(struct cmd_ent), compmi); if (res == NULL) { printf("cmd not found\n"); } else { res->fp(cmd); } } }




    熱門文章