The default implementations for __hash__ and __eq__ are inherited from the base object type. You can find its type definition in typeobject.c:
PyTypeObject PyBaseObject_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "object",                                   /* tp_name */
    …
    (hashfunc)_Py_HashPointer,                  /* tp_hash */
    …
    object_richcompare,                         /* tp_richcompare */
    …
};
For the hash function (tp_hash), the default hash function for references is used, _Py_HashPointer. It is defined in pyhash.c:
Py_hash_t
_Py_HashPointer(void *p)
{
    Py_hash_t x;
    size_t y = (size_t)p;
    /* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid
       excessive hash collisions for dicts and sets */
    y = (y >> 4) | (y << (8 * SIZEOF_VOID_P - 4));
    x = (Py_hash_t)y;
    if (x == -1)
        x = -2;
    return x;
}
This basically uses the pointer address as a base for the hash.
When __eq__ is called, what Python does under the hood is perform a rich comparison (tp_richcompare). This includes both equality and non-equality check as well as comparisons like greater or lower than. The default implementation is using object_richcompare which requires a reference equality:
static PyObject *
object_richcompare(PyObject *self, PyObject *other, int op)
{
    PyObject *res;
    switch (op) {
    case Py_EQ:
        /* Return NotImplemented instead of False, so if two
           objects are compared, both get a chance at the
           comparison.  See issue #1393. */
        res = (self == other) ? Py_True : Py_NotImplemented;
        Py_INCREF(res);
        break;
    …
    }
    return res;
}