1

We have made a Zend extension which we want to write the addresses of the zval's echo is supposed to write out, but we cannot figure how to receive them because we have noticed that there is difference between echo "test"; and $a = "test"; echo $a;

.... Some stuff that overrides the echo opcode ....

FILE *tmpfile;
int echo_handler(ZEND_OPCODE_HANDLER_ARGS)
{
    zend_op *opline = execute_data->opline;
    tmpfile = fopen("/tmp/echo.test","a+");
    fprintf(tmpfile,"Echo was called\n");
    fclose(tmpfile);

    return ZEND_USER_OPCODE_DISPATCH;
}

How do we get the arguments no matter if it is a variable or not?

Torben Pi Jensen
  • 850
  • 9
  • 27
  • See my answer. While it should work, I am wondering what do you need this for? Perhaps you're taking the wrong approach, or the right approach to the wrong problem. – Flavius Oct 04 '11 at 16:40
  • Well, We are trying to implement some sort of tainting in a module, and our approach is as follows(for VERY SIMPLE tainting) 1. On execution start, get the address of the zvals for $_GET elements (DONE) 2. On echo, get the address of the address of the zval to echo and check if it is one of the _GET zvals. (NOT DONE - Have hook on echo) Does this seem legit? – Torben Pi Jensen Oct 05 '11 at 07:16
  • Yes it does, for VERY SIMPLE tainting, as you said - my solution should work. In my (little) spare time I am working on something related: an extension which will empower php scripts with static code analysis features, that may be interesting for you as well. – Flavius Oct 05 '11 at 08:10
  • That sound really interesting, is it available anywhere? – Torben Pi Jensen Oct 05 '11 at 10:20
  • Sure, http://pecl.php.net/package/meta. It does not do much just yet, but it may be worth keeping an eye on it. – Flavius Oct 05 '11 at 10:43

1 Answers1

0

The handler for echo is

static int ZEND_FASTCALL  ZEND_ECHO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    zend_op *opline = EX(opline);

    zval z_copy;
    zval *z = &opline->op1.u.constant;

    if (IS_CONST != IS_CONST &&
        Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL &&
        zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
        zend_print_variable(&z_copy);
        zval_dtor(&z_copy);
    } else {
        zend_print_variable(z);
    }

    ZEND_VM_NEXT_OPCODE();
}

from Zend/zend_vm_execute.h, and as you can see all it basically does is to call zend_print_variable().

Hook that function and you should be on the right track.

Bonus: it works for print statements too.

Flavius
  • 13,566
  • 13
  • 80
  • 126
  • Now, I'm starting to get lost in the Zend code, I've been using the zend_set_user_opcode_handler(ZEND_ECHO, echo_handler); method to hook on echo's, which is triggered every time as planned, but the opline->op1.op_type is 4 (IS_VAR) and which means that op1.u.contant won't hold the zval with the value, however I figure out how to retrieve it from the execute_data... Is there any documentation available for the structure of execute_data besides the source code? – Torben Pi Jensen Oct 05 '11 at 12:18
  • EDIT: I can't figure out how to retrieve the zval from the execute_data, when op1.op_type is IS_VAR – Torben Pi Jensen Oct 05 '11 at 13:37
  • I'm still lost :/ The handler you refer is only for when op1.optype is IS_CONST, but the ZEND_ECHO_SPEC_VAR_HANDLER uses another way to access the zval of echo, however if I use the same approach as ZEND_ECHO_SPEC_VAR_HANDLER it tries to access some "random" data, as the pointer seems to be unset/not ever set. Is it possible to hook directly on the ZEND_ECHO_SPEC_VAR_HANDLER instead of on any echo opcode? – Torben Pi Jensen Oct 07 '11 at 07:45